[runtime] Migrate several Date builtins to C++.

Almost all of the Date builtins always call into C++ at least once
anyway, so parsing, compiling and executing the JavaScript wrappers
is just a waste of time.  The most important part here is the Date
constructor itself, which is one of the blockers for new.target in
TurboFan, because compiling the Date constructor takes too much time
with TurboFan (for no reason since we end up in C++ anway).

R=cbruni@chromium.org

Review URL: https://codereview.chromium.org/1556333002

Cr-Commit-Position: refs/heads/master@{#33109}
This commit is contained in:
bmeurer 2016-01-05 03:05:41 -08:00 committed by Commit bot
parent a94d6d6ede
commit 065e9c536f
18 changed files with 527 additions and 351 deletions

View File

@ -6043,8 +6043,9 @@ MaybeLocal<v8::Value> v8::Date::New(Local<Context> context, double time) {
}
PREPARE_FOR_EXECUTION(context, "Date::New", Value);
Local<Value> result;
has_pending_exception =
!ToLocal<Value>(i::Execution::NewDate(isolate, time), &result);
has_pending_exception = !ToLocal<Value>(
i::JSDate::New(isolate->date_function(), isolate->date_function(), time),
&result);
RETURN_ON_FAILED_EXECUTION(Value);
RETURN_ESCAPED(result);
}

View File

@ -1249,11 +1249,13 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
// Builtin functions for Date.prototype.
Handle<JSFunction> date_fun = InstallFunction(
global, "Date", JS_DATE_TYPE, JSDate::kSize,
isolate->initial_object_prototype(), Builtins::kIllegal);
isolate->initial_object_prototype(), Builtins::kDateConstructor);
InstallWithIntrinsicDefaultProto(isolate, date_fun,
Context::DATE_FUNCTION_INDEX);
date_fun->shared()->set_construct_stub(
*isolate->builtins()->JSBuiltinsConstructStub());
*isolate->builtins()->DateConstructor_ConstructStub());
date_fun->shared()->set_length(7);
date_fun->shared()->DontAdaptArguments();
}
{ // -- R e g E x p
@ -2530,21 +2532,36 @@ bool Genesis::InstallNatives(ContextType context_type) {
native_context()->set_global_eval_fun(*eval);
}
// Install Date.prototype[@@toPrimitive].
// Setup the Date constructor.
{
Handle<String> key = factory()->Date_string();
Handle<JSFunction> date = Handle<JSFunction>::cast(
Handle<JSFunction> date_fun = Handle<JSFunction>::cast(
Object::GetProperty(handle(native_context()->global_object()), key)
.ToHandleChecked());
Handle<JSObject> proto =
Handle<JSObject>(JSObject::cast(date->instance_prototype()));
Handle<JSObject> prototype =
Handle<JSObject>(JSObject::cast(date_fun->instance_prototype()));
// Install the Date.now, Date.parse and Date.UTC functions.
SimpleInstallFunction(date_fun, "now", Builtins::kDateNow, 0, false);
SimpleInstallFunction(date_fun, "parse", Builtins::kDateParse, 1, false);
SimpleInstallFunction(date_fun, "UTC", Builtins::kDateUTC, 7, false);
// Install the "constructor" property on the {prototype}.
JSObject::AddProperty(prototype, factory()->constructor_string(), date_fun,
DONT_ENUM);
// Install the toISOString and valueOf functions.
SimpleInstallFunction(prototype, "toISOString",
Builtins::kDatePrototypeToISOString, 0, false);
SimpleInstallFunction(prototype, "valueOf", Builtins::kDatePrototypeValueOf,
0, false);
// Install the @@toPrimitive function.
Handle<JSFunction> to_primitive =
InstallFunction(proto, factory()->to_primitive_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, MaybeHandle<JSObject>(),
Builtins::kDateToPrimitive,
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
Handle<JSFunction> to_primitive = InstallFunction(
prototype, factory()->to_primitive_symbol(), JS_OBJECT_TYPE,
JSObject::kHeaderSize, MaybeHandle<JSObject>(),
Builtins::kDatePrototypeToPrimitive,
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
// Set the expected parameters for @@toPrimitive to 1; required by builtin.
to_primitive->shared()->set_internal_formal_parameter_count(1);

View File

@ -9,6 +9,7 @@
#include "src/arguments.h"
#include "src/base/once.h"
#include "src/bootstrapper.h"
#include "src/dateparser-inl.h"
#include "src/elements.h"
#include "src/frames-inl.h"
#include "src/gdb-jit.h"
@ -148,6 +149,17 @@ BUILTIN_LIST_C(DEF_ARG_TYPE)
// ----------------------------------------------------------------------------
#define CHECK_RECEIVER(Type, name, method) \
if (!args.receiver()->Is##Type()) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, \
NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \
isolate->factory()->NewStringFromAsciiChecked(method), \
args.receiver())); \
} \
Handle<Type> name = Handle<Type>::cast(args.receiver())
inline bool ClampedToInteger(Object* object, int* out) {
// This is an extended version of ECMA-262 7.1.11 handling signed values
// Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
@ -1938,18 +1950,384 @@ BUILTIN(ReflectSetPrototypeOf) {
}
// -----------------------------------------------------------------------------
// ES6 section 20.3 Date Objects
namespace {
// ES6 section 20.3.1.1 Time Values and Time Range
const double kMinYear = -1000000.0;
const double kMaxYear = -kMinYear;
const double kMinMonth = -10000000.0;
const double kMaxMonth = -kMinMonth;
// 20.3.1.2 Day Number and Time within Day
const double kMsPerDay = 86400000.0;
// ES6 section 20.3.1.11 Hours, Minutes, Second, and Milliseconds
const double kMsPerSecond = 1000.0;
const double kMsPerMinute = 60000.0;
const double kMsPerHour = 3600000.0;
// ES6 section 20.3.1.14 MakeDate (day, time)
double MakeDate(double day, double time) {
if (std::isfinite(day) && std::isfinite(time)) {
return time + day * kMsPerDay;
}
return std::numeric_limits<double>::quiet_NaN();
}
// ES6 section 20.3.1.13 MakeDay (year, month, date)
double MakeDay(double year, double month, double date) {
if ((kMinYear <= year && year <= kMaxYear) &&
(kMinMonth <= month && month <= kMaxMonth) && std::isfinite(date)) {
int y = FastD2I(year);
int m = FastD2I(month);
y += m / 12;
m %= 12;
if (m < 0) {
m += 12;
y -= 1;
}
DCHECK_LE(0, m);
DCHECK_LT(m, 12);
// kYearDelta is an arbitrary number such that:
// a) kYearDelta = -1 (mod 400)
// b) year + kYearDelta > 0 for years in the range defined by
// ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
// Jan 1 1970. This is required so that we don't run into integer
// division of negative numbers.
// c) there shouldn't be an overflow for 32-bit integers in the following
// operations.
static const int kYearDelta = 399999;
static const int kBaseDay =
365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 -
(1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400;
int day_from_year = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 -
(y + kYearDelta) / 100 + (y + kYearDelta) / 400 -
kBaseDay;
if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) {
static const int kDayFromMonth[] = {0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334};
day_from_year += kDayFromMonth[m];
} else {
static const int kDayFromMonth[] = {0, 31, 60, 91, 121, 152,
182, 213, 244, 274, 305, 335};
day_from_year += kDayFromMonth[m];
}
return static_cast<double>(day_from_year - 1) + date;
}
return std::numeric_limits<double>::quiet_NaN();
}
// ES6 section 20.3.1.12 MakeTime (hour, min, sec, ms)
double MakeTime(double hour, double min, double sec, double ms) {
if (std::isfinite(hour) && std::isfinite(min) && std::isfinite(sec) &&
std::isfinite(ms)) {
double const h = DoubleToInteger(hour);
double const m = DoubleToInteger(min);
double const s = DoubleToInteger(sec);
double const milli = DoubleToInteger(ms);
return h * kMsPerHour + m * kMsPerMinute + s * kMsPerSecond + milli;
}
return std::numeric_limits<double>::quiet_NaN();
}
// ES6 section 20.3.1.15 TimeClip (time)
double TimeClip(double time) {
if (-DateCache::kMaxTimeInMs <= time && time <= DateCache::kMaxTimeInMs) {
return DoubleToInteger(time) + 0.0;
}
return std::numeric_limits<double>::quiet_NaN();
}
const char* kShortWeekDays[] = {"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"};
const char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
// ES6 section 20.3.1.16 Date Time String Format
double ParseDateTimeString(Handle<String> str) {
Isolate* const isolate = str->GetIsolate();
str = String::Flatten(str);
// TODO(bmeurer): Change DateParser to not use the FixedArray.
Handle<FixedArray> tmp =
isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE);
DisallowHeapAllocation no_gc;
String::FlatContent str_content = str->GetFlatContent();
bool result;
if (str_content.IsOneByte()) {
result = DateParser::Parse(str_content.ToOneByteVector(), *tmp,
isolate->unicode_cache());
} else {
result = DateParser::Parse(str_content.ToUC16Vector(), *tmp,
isolate->unicode_cache());
}
if (!result) return std::numeric_limits<double>::quiet_NaN();
double const day = MakeDay(tmp->get(0)->Number(), tmp->get(1)->Number(),
tmp->get(2)->Number());
double const time = MakeTime(tmp->get(3)->Number(), tmp->get(4)->Number(),
tmp->get(5)->Number(), tmp->get(6)->Number());
double date = MakeDate(day, time);
if (tmp->get(7)->IsNull()) {
date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date));
} else {
date -= tmp->get(7)->Number() * 1000.0;
}
return date;
}
// ES6 section 20.3.4.41.1 ToDateString(tv)
void ToDateString(double time_val, Vector<char> str, DateCache* date_cache) {
if (std::isnan(time_val)) {
SNPrintF(str, "Invalid Date");
} else {
int64_t time_ms = static_cast<int64_t>(time_val);
int64_t local_time_ms = date_cache->ToLocal(time_ms);
int year, month, day, weekday, hour, min, sec, ms;
date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday,
&hour, &min, &sec, &ms);
int timezone_offset = -date_cache->TimezoneOffset(time_ms);
int timezone_hour = std::abs(timezone_offset) / 60;
int timezone_min = std::abs(timezone_offset) % 60;
const char* local_timezone = date_cache->LocalTimezone(time_ms);
SNPrintF(str, "%s %s %02d %4d %02d:%02d:%02d GMT%c%02d%02d (%s)",
kShortWeekDays[weekday], kShortMonths[month], day, year, hour, min,
sec, (timezone_offset < 0) ? '-' : '+', timezone_hour,
timezone_min, local_timezone);
}
}
} // namespace
// ES6 section 20.3.2 The Date Constructor for the [[Call]] case.
BUILTIN(DateConstructor) {
HandleScope scope(isolate);
double const time_val = JSDate::CurrentTimeValue(isolate);
char buffer[128];
Vector<char> str(buffer, arraysize(buffer));
ToDateString(time_val, str, isolate->date_cache());
return *isolate->factory()->NewStringFromAsciiChecked(str.start());
}
// ES6 section 20.3.2 The Date Constructor for the [[Construct]] case.
BUILTIN(DateConstructor_ConstructStub) {
HandleScope scope(isolate);
int const argc = args.length() - 1;
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
double time_val;
if (argc == 0) {
time_val = JSDate::CurrentTimeValue(isolate);
} else if (argc == 1) {
Handle<Object> value = args.at<Object>(1);
if (value->IsJSDate()) {
time_val = Handle<JSDate>::cast(value)->value()->Number();
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
Object::ToPrimitive(value));
if (value->IsString()) {
time_val = ParseDateTimeString(Handle<String>::cast(value));
} else {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
Object::ToNumber(value));
time_val = value->Number();
}
}
} else {
Handle<Object> year_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
Object::ToNumber(args.at<Object>(1)));
Handle<Object> month_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
Object::ToNumber(args.at<Object>(2)));
double year = year_object->Number();
double month = month_object->Number();
double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0;
if (argc >= 3) {
Handle<Object> date_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object,
Object::ToNumber(args.at<Object>(3)));
date = date_object->Number();
if (argc >= 4) {
Handle<Object> hours_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, hours_object, Object::ToNumber(args.at<Object>(4)));
hours = hours_object->Number();
if (argc >= 5) {
Handle<Object> minutes_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, minutes_object, Object::ToNumber(args.at<Object>(5)));
minutes = minutes_object->Number();
if (argc >= 6) {
Handle<Object> seconds_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, seconds_object, Object::ToNumber(args.at<Object>(6)));
seconds = seconds_object->Number();
if (argc >= 7) {
Handle<Object> ms_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, ms_object, Object::ToNumber(args.at<Object>(7)));
ms = ms_object->Number();
}
}
}
}
}
if (!std::isnan(year)) {
double const y = DoubleToInteger(year);
if (0.0 <= y && y <= 99) year = 1900 + y;
}
double const day = MakeDay(year, month, date);
double const time = MakeTime(hours, minutes, seconds, ms);
time_val = MakeDate(day, time);
if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
} else {
time_val = std::numeric_limits<double>::quiet_NaN();
}
}
Handle<JSDate> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
JSDate::New(target, new_target, time_val));
return *result;
}
// ES6 section 20.3.3.1 Date.now ( )
BUILTIN(DateNow) {
HandleScope scope(isolate);
return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate));
}
// ES6 section 20.3.3.2 Date.parse ( string )
BUILTIN(DateParse) {
HandleScope scope(isolate);
Handle<String> string;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, string,
Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
return *isolate->factory()->NewNumber(ParseDateTimeString(string));
}
// ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms)
BUILTIN(DateUTC) {
HandleScope scope(isolate);
int const argc = args.length() - 1;
double year = std::numeric_limits<double>::quiet_NaN();
double month = std::numeric_limits<double>::quiet_NaN();
double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0;
if (argc >= 1) {
Handle<Object> year_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
Object::ToNumber(args.at<Object>(1)));
year = year_object->Number();
if (argc >= 2) {
Handle<Object> month_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
Object::ToNumber(args.at<Object>(2)));
month = month_object->Number();
if (argc >= 3) {
Handle<Object> date_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, date_object, Object::ToNumber(args.at<Object>(3)));
date = date_object->Number();
if (argc >= 4) {
Handle<Object> hours_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, hours_object, Object::ToNumber(args.at<Object>(4)));
hours = hours_object->Number();
if (argc >= 5) {
Handle<Object> minutes_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, minutes_object, Object::ToNumber(args.at<Object>(5)));
minutes = minutes_object->Number();
if (argc >= 6) {
Handle<Object> seconds_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, seconds_object,
Object::ToNumber(args.at<Object>(6)));
seconds = seconds_object->Number();
if (argc >= 7) {
Handle<Object> ms_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, ms_object, Object::ToNumber(args.at<Object>(7)));
ms = ms_object->Number();
}
}
}
}
}
}
}
if (!std::isnan(year)) {
double const y = DoubleToInteger(year);
if (0.0 <= y && y <= 99) year = 1900 + y;
}
double const day = MakeDay(year, month, date);
double const time = MakeTime(hours, minutes, seconds, ms);
return *isolate->factory()->NewNumber(TimeClip(MakeDate(day, time)));
}
// ES6 section 20.3.4.36 Date.prototype.toISOString ( )
BUILTIN(DatePrototypeToISOString) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString");
double const time_val = date->value()->Number();
if (std::isnan(time_val)) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
}
int64_t const time_ms = static_cast<int64_t>(time_val);
int year, month, day, weekday, hour, min, sec, ms;
isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
&hour, &min, &sec, &ms);
char buffer[128];
Vector<char> str(buffer, arraysize(buffer));
if (year >= 0 && year <= 9999) {
SNPrintF(str, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, month + 1, day,
hour, min, sec, ms);
} else if (year < 0) {
SNPrintF(str, "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", -year, month + 1, day,
hour, min, sec, ms);
} else {
SNPrintF(str, "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, month + 1, day,
hour, min, sec, ms);
}
return *isolate->factory()->NewStringFromAsciiChecked(str.start());
}
// ES6 section 20.3.4.44 Date.prototype.valueOf ( )
BUILTIN(DatePrototypeValueOf) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSDate, date, "Date.prototype.valueOf");
return date->value();
}
// ES6 section 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
BUILTIN(DateToPrimitive) {
BUILTIN(DatePrototypeToPrimitive) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
if (!args.receiver()->IsJSReceiver()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
isolate->factory()->NewStringFromAsciiChecked(
"Date.prototype [ @@toPrimitive ]"),
args.receiver()));
}
Handle<JSReceiver> receiver = args.at<JSReceiver>(0);
CHECK_RECEIVER(JSReceiver, receiver, "Date.prototype [ @@toPrimitive ]");
Handle<Object> hint = args.at<Object>(1);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,

View File

@ -69,7 +69,14 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(ArrayBufferConstructor_ConstructStub, kTargetAndNewTarget) \
V(ArrayBufferIsView, kNone) \
\
V(DateToPrimitive, kNone) \
V(DateConstructor, kNone) \
V(DateConstructor_ConstructStub, kTargetAndNewTarget) \
V(DateNow, kNone) \
V(DateParse, kNone) \
V(DateUTC, kNone) \
V(DatePrototypeToISOString, kNone) \
V(DatePrototypeToPrimitive, kNone) \
V(DatePrototypeValueOf, kNone) \
\
V(FunctionConstructor, kTargetAndNewTarget) \
V(FunctionPrototypeBind, kNone) \

View File

@ -109,7 +109,6 @@ enum BindingFlags {
V(ARRAY_SLICE_INDEX, JSFunction, array_slice) \
V(ARRAY_UNSHIFT_INDEX, JSFunction, array_unshift) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \

View File

@ -175,6 +175,20 @@ int DateCache::DaysFromYearMonth(int year, int month) {
}
void DateCache::BreakDownTime(int64_t time_ms, int* year, int* month, int* day,
int* weekday, int* hour, int* min, int* sec,
int* ms) {
int const days = DaysFromTime(time_ms);
int const time_in_day_ms = TimeInDay(time_ms, days);
YearMonthDayFromDays(days, year, month, day);
*weekday = Weekday(days);
*hour = time_in_day_ms / (60 * 60 * 1000);
*min = (time_in_day_ms / (60 * 1000)) % 60;
*sec = (time_in_day_ms / 1000) % 60;
*ms = time_in_day_ms % 1000;
}
void DateCache::ExtendTheAfterSegment(int time_sec, int offset_ms) {
if (after_->offset_ms == offset_ms &&
after_->start_sec <= time_sec + kDefaultDSTDeltaInSec &&

View File

@ -190,6 +190,10 @@ class DateCache {
// the first day of the given month in the given year.
int DaysFromYearMonth(int year, int month);
// Breaks down the time value.
void BreakDownTime(int64_t time_ms, int* year, int* month, int* day,
int* weekday, int* hour, int* min, int* sec, int* ms);
// Cache stamp is used for invalidating caches in JSDate.
// We increment the stamp each time when the timezone information changes.
// JSDate objects perform stamp check and invalidate their caches if

View File

@ -6,7 +6,6 @@
#include "src/bootstrapper.h"
#include "src/codegen.h"
#include "src/deoptimizer.h"
#include "src/isolate-inl.h"
#include "src/messages.h"
#include "src/vm-state-inl.h"
@ -421,22 +420,6 @@ void StackGuard::InitThread(const ExecutionAccess& lock) {
// --- C a l l s t o n a t i v e s ---
#define RETURN_NATIVE_CALL(name, args) \
do { \
Handle<Object> argv[] = args; \
return Call(isolate, isolate->name##_fun(), \
isolate->factory()->undefined_value(), arraysize(argv), argv); \
} while (false)
MaybeHandle<Object> Execution::NewDate(Isolate* isolate, double time) {
Handle<Object> time_obj = isolate->factory()->NewNumber(time);
RETURN_NATIVE_CALL(create_date, { time_obj });
}
#undef RETURN_NATIVE_CALL
MaybeHandle<Object> Execution::ToObject(Isolate* isolate, Handle<Object> obj) {
Handle<JSReceiver> receiver;

View File

@ -13,9 +13,6 @@
namespace v8 {
namespace internal {
// Forward declarations.
class JSRegExp;
class Execution final : public AllStatic {
public:
// Call a function, the caller supplies a receiver and an array
@ -56,10 +53,6 @@ class Execution final : public AllStatic {
MUST_USE_RESULT static MaybeHandle<Object> ToObject(
Isolate* isolate, Handle<Object> obj);
// Create a new date object from 'time'.
MUST_USE_RESULT static MaybeHandle<Object> NewDate(
Isolate* isolate, double time);
static Handle<String> GetStackTraceLine(Handle<Object> recv,
Handle<JSFunction> fun,
Handle<Object> pos,

View File

@ -49,14 +49,6 @@ function LocalTimezone(t) {
}
function UTC(time) {
if (NUMBER_IS_NAN(time)) return time;
// local_time_offset is needed before the call to DaylightSavingsOffset,
// so it may be uninitialized.
return %DateToUTC(time);
}
// ECMA 262 - 15.9.1.11
function MakeTime(hour, min, sec, ms) {
if (!IsFinite(hour)) return NaN;
@ -115,80 +107,6 @@ function TimeClip(time) {
}
// The Date cache is used to limit the cost of parsing the same Date
// strings over and over again.
var Date_cache = {
// Cached time value.
time: 0,
// String input for which the cached time is valid.
string: null
};
function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
if (IS_UNDEFINED(new.target)) {
// ECMA 262 - 15.9.2
return %_Call(DateToString, new GlobalDate());
}
// ECMA 262 - 15.9.3
var argc = %_ArgumentsLength();
var value;
var result;
if (argc == 0) {
value = %DateCurrentTime();
result = %NewObject(GlobalDate, new.target);
SET_UTC_DATE_VALUE(result, value);
} else if (argc == 1) {
if (IS_NUMBER(year)) {
value = TimeClip(year);
} else if (IS_STRING(year)) {
// Probe the Date cache. If we already have a time value for the
// given time, we re-use that instead of parsing the string again.
CheckDateCacheCurrent();
var cache = Date_cache;
if (cache.string === year) {
value = cache.time;
} else {
value = DateParse(year);
if (!NUMBER_IS_NAN(value)) {
cache.time = value;
cache.string = year;
}
}
} else if (IS_DATE(year)) {
value = UTC_DATE_VALUE(year);
} else {
var time = TO_PRIMITIVE(year);
value = IS_STRING(time) ? DateParse(time) : TO_NUMBER(time);
}
result = %NewObject(GlobalDate, new.target);
SET_UTC_DATE_VALUE(result, value);
} else {
year = TO_NUMBER(year);
month = TO_NUMBER(month);
date = argc > 2 ? TO_NUMBER(date) : 1;
hours = argc > 3 ? TO_NUMBER(hours) : 0;
minutes = argc > 4 ? TO_NUMBER(minutes) : 0;
seconds = argc > 5 ? TO_NUMBER(seconds) : 0;
ms = argc > 6 ? TO_NUMBER(ms) : 0;
year = (!NUMBER_IS_NAN(year) &&
0 <= TO_INTEGER(year) &&
TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
var day = MakeDay(year, month, date);
var time = MakeTime(hours, minutes, seconds, ms);
value = MakeDate(day, time);
result = %NewObject(GlobalDate, new.target);
SET_LOCAL_DATE_VALUE(result, value);
}
return result;
}
var WeekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var Months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
@ -260,51 +178,6 @@ function DatePrintString(date) {
// -------------------------------------------------------------------
// Reused output buffer. Used when parsing date strings.
var parse_buffer = new InternalArray(8);
// ECMA 262 - 15.9.4.2
function DateParse(string) {
var arr = %DateParseString(string, parse_buffer);
if (IS_NULL(arr)) return NaN;
var day = MakeDay(arr[0], arr[1], arr[2]);
var time = MakeTime(arr[3], arr[4], arr[5], arr[6]);
var date = MakeDate(day, time);
if (IS_NULL(arr[7])) {
return TimeClip(UTC(date));
} else {
return TimeClip(date - arr[7] * 1000);
}
}
// ECMA 262 - 15.9.4.3
function DateUTC(year, month, date, hours, minutes, seconds, ms) {
year = TO_NUMBER(year);
month = TO_NUMBER(month);
var argc = %_ArgumentsLength();
date = argc > 2 ? TO_NUMBER(date) : 1;
hours = argc > 3 ? TO_NUMBER(hours) : 0;
minutes = argc > 4 ? TO_NUMBER(minutes) : 0;
seconds = argc > 5 ? TO_NUMBER(seconds) : 0;
ms = argc > 6 ? TO_NUMBER(ms) : 0;
year = (!NUMBER_IS_NAN(year) &&
0 <= TO_INTEGER(year) &&
TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
var day = MakeDay(year, month, date);
var time = MakeTime(hours, minutes, seconds, ms);
return TimeClip(MakeDate(day, time));
}
// ECMA 262 - 15.9.4.4
function DateNow() {
return %DateCurrentTime();
}
// ECMA 262 - 15.9.5.2
function DateToString() {
CHECK_DATE(this);
@ -359,13 +232,6 @@ function DateToLocaleTimeString() {
}
// ECMA 262 - 15.9.5.8
function DateValueOf() {
CHECK_DATE(this);
return UTC_DATE_VALUE(this);
}
// ECMA 262 - 15.9.5.9
function DateGetTime() {
CHECK_DATE(this);
@ -739,39 +605,6 @@ function DateToGMTString() {
}
function PadInt(n, digits) {
if (digits == 1) return n;
return n < %_MathPow(10, digits - 1) ? '0' + PadInt(n, digits - 1) : n;
}
// ECMA 262 - 20.3.4.36
function DateToISOString() {
CHECK_DATE(this);
var t = UTC_DATE_VALUE(this);
if (NUMBER_IS_NAN(t)) throw MakeRangeError(kInvalidTimeValue);
var year = UTC_YEAR(this);
var year_string;
if (year >= 0 && year <= 9999) {
year_string = PadInt(year, 4);
} else {
if (year < 0) {
year_string = "-" + PadInt(-year, 6);
} else {
year_string = "+" + PadInt(year, 6);
}
}
return year_string +
'-' + PadInt(UTC_MONTH(this) + 1, 2) +
'-' + PadInt(UTC_DAY(this), 2) +
'T' + PadInt(UTC_HOUR(this), 2) +
':' + PadInt(UTC_MIN(this), 2) +
':' + PadInt(UTC_SEC(this), 2) +
'.' + PadInt(UTC_MS(this), 3) +
'Z';
}
// 20.3.4.37 Date.prototype.toJSON ( key )
function DateToJSON(key) {
var o = TO_OBJECT(this);
@ -800,34 +633,12 @@ function CheckDateCacheCurrent() {
// Reset the timezone cache:
timezone_cache_time = NaN;
timezone_cache_timezone = UNDEFINED;
// Reset the date cache:
Date_cache.time = NaN;
Date_cache.string = null;
}
function CreateDate(time) {
var date = new GlobalDate();
date.setTime(time);
return date;
}
// -------------------------------------------------------------------
%SetCode(GlobalDate, DateConstructor);
%FunctionSetPrototype(GlobalDate, new GlobalObject());
// Set up non-enumerable properties of the Date object itself.
utils.InstallFunctions(GlobalDate, DONT_ENUM, [
"UTC", DateUTC,
"parse", DateParse,
"now", DateNow
]);
// Set up non-enumerable constructor property of the Date prototype object.
%AddNamedProperty(GlobalDate.prototype, "constructor", GlobalDate, DONT_ENUM);
// Set up non-enumerable functions of the Date prototype object and
// set their names.
utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [
@ -837,7 +648,6 @@ utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [
"toLocaleString", DateToLocaleString,
"toLocaleDateString", DateToLocaleDateString,
"toLocaleTimeString", DateToLocaleTimeString,
"valueOf", DateValueOf,
"getTime", DateGetTime,
"getFullYear", DateGetFullYear,
"getUTCFullYear", DateGetUTCFullYear,
@ -875,10 +685,7 @@ utils.InstallFunctions(GlobalDate.prototype, DONT_ENUM, [
"toUTCString", DateToUTCString,
"getYear", DateGetYear,
"setYear", DateSetYear,
"toISOString", DateToISOString,
"toJSON", DateToJSON
]);
%InstallToContext(["create_date_fun", CreateDate]);
})

View File

@ -1027,6 +1027,33 @@ Object* FunctionTemplateInfo::GetCompatibleReceiver(Isolate* isolate,
}
// static
MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
Handle<AllocationSite> site) {
// If called through new, new.target can be:
// - a subclass of constructor,
// - a proxy wrapper around constructor, or
// - the constructor itself.
// If called through Reflect.construct, it's guaranteed to be a constructor.
Isolate* const isolate = constructor->GetIsolate();
DCHECK(constructor->IsConstructor());
DCHECK(new_target->IsConstructor());
DCHECK(!constructor->has_initial_map() ||
constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
Handle<Map> initial_map;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, initial_map,
JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
Handle<JSObject> result =
isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
isolate->counters()->constructed_objects()->Increment();
isolate->counters()->constructed_objects_runtime()->Increment();
return result;
}
Handle<FixedArray> JSObject::EnsureWritableFastElements(
Handle<JSObject> object) {
DCHECK(object->HasFastSmiOrObjectElements());
@ -19094,6 +19121,39 @@ int BreakPointInfo::GetBreakPointCount() {
}
// static
MaybeHandle<JSDate> JSDate::New(Handle<JSFunction> constructor,
Handle<JSReceiver> new_target, double tv) {
Isolate* const isolate = constructor->GetIsolate();
Handle<JSObject> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
JSObject::New(constructor, new_target), JSDate);
if (-DateCache::kMaxTimeInMs <= tv && tv <= DateCache::kMaxTimeInMs) {
tv = DoubleToInteger(tv) + 0.0;
} else {
tv = std::numeric_limits<double>::quiet_NaN();
}
Handle<Object> value = isolate->factory()->NewNumber(tv);
Handle<JSDate>::cast(result)->SetValue(*value, std::isnan(tv));
return Handle<JSDate>::cast(result);
}
// static
double JSDate::CurrentTimeValue(Isolate* isolate) {
if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
// According to ECMA-262, section 15.9.1, page 117, the precision of
// the number in a Date object representing a particular instant in
// time is milliseconds. Therefore, we floor the result of getting
// the OS time.
return Floor(FLAG_verify_predictable
? isolate->heap()->MonotonicallyIncreasingTimeInMs()
: base::OS::TimeCurrentMillis());
}
// static
Object* JSDate::GetField(Object* object, Smi* index) {
return JSDate::cast(object)->DoGetField(
static_cast<FieldIndex>(index->value()));

View File

@ -1967,6 +1967,10 @@ class JSReceiver: public HeapObject {
// caching.
class JSObject: public JSReceiver {
public:
static MUST_USE_RESULT MaybeHandle<JSObject> New(
Handle<JSFunction> constructor, Handle<JSReceiver> new_target,
Handle<AllocationSite> site = Handle<AllocationSite>::null());
// [properties]: Backing storage for properties.
// properties is a FixedArray in the fast case and a Dictionary in the
// slow case.
@ -7530,6 +7534,10 @@ class DateCache;
// Representation for JS date objects.
class JSDate: public JSObject {
public:
static MUST_USE_RESULT MaybeHandle<JSDate> New(Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
double tv);
// If one component is NaN, all of them are, indicating a NaN time value.
// [value]: the time value.
DECL_ACCESSORS(value, Object)
@ -7553,6 +7561,9 @@ class JSDate: public JSObject {
DECLARE_CAST(JSDate)
// Returns the time value (UTC) identifying the current time.
static double CurrentTimeValue(Isolate* isolate);
// Returns the date field with the specified index.
// See FieldIndex for the list of date fields.
static Object* GetField(Object* date, Smi* index);

View File

@ -7,7 +7,6 @@
#include "src/arguments.h"
#include "src/conversions-inl.h"
#include "src/date.h"
#include "src/dateparser-inl.h"
#include "src/factory.h"
#include "src/isolate-inl.h"
#include "src/messages.h"
@ -79,58 +78,8 @@ RUNTIME_FUNCTION(Runtime_ThrowNotDateError) {
RUNTIME_FUNCTION(Runtime_DateCurrentTime) {
HandleScope scope(isolate);
DCHECK(args.length() == 0);
if (FLAG_log_timer_events || FLAG_prof_cpp) LOG(isolate, CurrentTimeEvent());
// According to ECMA-262, section 15.9.1, page 117, the precision of
// the number in a Date object representing a particular instant in
// time is milliseconds. Therefore, we floor the result of getting
// the OS time.
double millis;
if (FLAG_verify_predictable) {
millis = Floor(isolate->heap()->MonotonicallyIncreasingTimeInMs());
} else {
millis = Floor(base::OS::TimeCurrentMillis());
}
return *isolate->factory()->NewNumber(millis);
}
RUNTIME_FUNCTION(Runtime_DateParseString) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
RUNTIME_ASSERT(output->HasFastElements());
JSObject::EnsureCanContainHeapObjectElements(output);
RUNTIME_ASSERT(output->HasFastObjectElements());
Handle<FixedArray> output_array(FixedArray::cast(output->elements()));
RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
Handle<String> str;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, str,
Object::ToString(isolate, input));
str = String::Flatten(str);
DisallowHeapAllocation no_gc;
bool result;
String::FlatContent str_content = str->GetFlatContent();
if (str_content.IsOneByte()) {
result = DateParser::Parse(str_content.ToOneByteVector(), *output_array,
isolate->unicode_cache());
} else {
DCHECK(str_content.IsTwoByte());
result = DateParser::Parse(str_content.ToUC16Vector(), *output_array,
isolate->unicode_cache());
}
if (result) {
return *output;
} else {
return isolate->heap()->null_value();
}
DCHECK_EQ(0, args.length());
return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate));
}
@ -149,19 +98,6 @@ RUNTIME_FUNCTION(Runtime_DateLocalTimezone) {
}
RUNTIME_FUNCTION(Runtime_DateToUTC) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
RUNTIME_ASSERT(x >= -DateCache::kMaxTimeBeforeUTCInMs &&
x <= DateCache::kMaxTimeBeforeUTCInMs);
int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
return *isolate->factory()->NewNumber(static_cast<double>(time));
}
RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
HandleScope hs(isolate);
DCHECK(args.length() == 0);

View File

@ -389,10 +389,11 @@ RUNTIME_FUNCTION(Runtime_InternalDateParse) {
UDate date = date_format->parse(u_date, status);
if (U_FAILURE(status)) return isolate->heap()->undefined_value();
Handle<Object> result;
Handle<JSDate> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result, Execution::NewDate(isolate, static_cast<double>(date)));
DCHECK(result->IsJSDate());
isolate, result,
JSDate::New(isolate->date_function(), isolate->date_function(),
static_cast<double>(date)));
return *result;
}

View File

@ -795,46 +795,15 @@ RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
}
static Object* Runtime_NewObjectHelper(Isolate* isolate,
Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
Handle<AllocationSite> site) {
DCHECK(constructor->IsConstructor());
// If called through new, new.target can be:
// - a subclass of constructor,
// - a proxy wrapper around constructor, or
// - the constructor itself.
// If called through Reflect.construct, it's guaranteed to be a constructor by
// REFLECT_CONSTRUCT_PREPARE.
DCHECK(new_target->IsConstructor());
DCHECK(!constructor->has_initial_map() ||
constructor->initial_map()->instance_type() != JS_FUNCTION_TYPE);
Handle<Map> initial_map;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, initial_map,
JSFunction::GetDerivedMap(isolate, constructor, new_target));
Handle<JSObject> result =
isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
isolate->counters()->constructed_objects()->Increment();
isolate->counters()->constructed_objects_runtime()->Increment();
return *result;
}
RUNTIME_FUNCTION(Runtime_NewObject) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1);
return Runtime_NewObjectHelper(isolate, constructor, new_target,
Handle<AllocationSite>::null());
Handle<JSObject> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
JSObject::New(target, new_target));
return *result;
}

View File

@ -141,9 +141,7 @@ namespace internal {
F(IsDate, 1, 1) \
F(ThrowNotDateError, 0, 1) \
F(DateCurrentTime, 0, 1) \
F(DateParseString, 2, 1) \
F(DateLocalTimezone, 1, 1) \
F(DateToUTC, 1, 1) \
F(DateCacheVersion, 0, 1) \
F(DateField, 2 /* date object, field index */, 1)

View File

@ -75,7 +75,6 @@ testTraceNativeConversion(RegExp); // Does ToString on argument.
testTraceNativeConstructor(String); // Does ToString on argument.
testTraceNativeConstructor(Number); // Does ToNumber on argument.
testTraceNativeConstructor(RegExp); // Does ToString on argument.
testTraceNativeConstructor(Date); // Does ToNumber on argument.
// QuickSort has builtins object as receiver, and is non-native
// builtin. Should not be omitted with the --builtins-in-stack-traces flag.

View File

@ -297,7 +297,6 @@ testTraceNativeConversion(RegExp); // Does ToString on argument.
testTraceNativeConstructor(String); // Does ToString on argument.
testTraceNativeConstructor(Number); // Does ToNumber on argument.
testTraceNativeConstructor(RegExp); // Does ToString on argument.
testTraceNativeConstructor(Date); // Does ToNumber on argument.
// Omitted because QuickSort has builtins object as receiver, and is non-native
// builtin.