Commit 126e88db authored by Ujjwal Sharma's avatar Ujjwal Sharma Committed by Commit Bot

[intl] Port DateTimeFormat.prototype.format and bound format function to C++

This increases the size of a DateFormat instance by a word to store
the bound format function.

The instance to be bound is stored on the context of this builtin function.

Bug: v8:7800
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I05968251d3411f5126dba3ce9b5b6b29836fd5dc
Reviewed-on: https://chromium-review.googlesource.com/1178763
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55240}
parent 8e57cd51
......@@ -2912,6 +2912,17 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleInstallFunction(isolate_, prototype, "formatToParts",
Builtins::kDateTimeFormatPrototypeFormatToParts, 1,
false);
SimpleInstallGetter(isolate_, prototype,
factory->InternalizeUtf8String("format"),
Builtins::kDateTimeFormatPrototypeFormat, false);
{
Handle<SharedFunctionInfo> info = SimpleCreateBuiltinSharedFunctionInfo(
isolate_, Builtins::kDateTimeFormatInternalFormat,
factory->empty_string(), 1);
native_context()->set_date_format_internal_format_shared_fun(*info);
}
}
{
......
......@@ -1371,6 +1371,10 @@ namespace internal {
CPP(NumberFormatInternalFormatNumber) \
/* ecma402 #sec-intl.numberformat.prototype.format */ \
CPP(NumberFormatPrototypeFormatNumber) \
/* ecma402 #sec-datetime-format-functions */ \
CPP(DateTimeFormatInternalFormat) \
/* ecma402 #sec-intl.datetimeformat.prototype.format */ \
CPP(DateTimeFormatPrototypeFormat) \
/* ecma402 #sec-intl.pluralrules */ \
CPP(PluralRulesConstructor) \
/* ecma402 #sec-intl.RelativeTimeFormat.constructor */ \
......
......@@ -594,6 +594,78 @@ BUILTIN(NumberFormatInternalFormatNumber) {
isolate, number_format_holder, number));
}
BUILTIN(DateTimeFormatPrototypeFormat) {
const char* const method = "get Intl.DateTimeFormat.prototype.format";
HandleScope scope(isolate);
// 1. Let dtf be this value.
// 2. If Type(dtf) is not Object, throw a TypeError exception.
CHECK_RECEIVER(JSReceiver, receiver, method);
// 3. Let dtf be ? UnwrapDateTimeFormat(dtf).
Handle<JSObject> date_format_holder;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, date_format_holder,
DateFormat::Unwrap(isolate, receiver, method));
DCHECK(Intl::IsObjectOfType(isolate, date_format_holder,
Intl::Type::kDateTimeFormat));
Handle<Object> bound_format = Handle<Object>(
date_format_holder->GetEmbedderField(DateFormat::kBoundFormatIndex),
isolate);
// 4. If dtf.[[BoundFormat]] is undefined, then
if (!bound_format->IsUndefined(isolate)) {
DCHECK(bound_format->IsJSFunction());
// 5. Return dtf.[[BoundFormat]].
return *bound_format;
}
Handle<Context> native_context =
Handle<Context>(isolate->context()->native_context(), isolate);
Handle<Context> context = isolate->factory()->NewBuiltinContext(
native_context, DateFormat::ContextSlot::kLength);
// 4.b. Set F.[[DateTimeFormat]] to dtf.
context->set(DateFormat::ContextSlot::kDateFormat, *date_format_holder);
Handle<SharedFunctionInfo> info = Handle<SharedFunctionInfo>(
native_context->date_format_internal_format_shared_fun(), isolate);
Handle<Map> map = isolate->strict_function_without_prototype_map();
// 4.a. Let F be a new built-in function object as defined in DateTime Format
// Functions (12.1.5).
Handle<JSFunction> new_bound_format_function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);
// 4.c. Set dtf.[[BoundFormat]] to F.
date_format_holder->SetEmbedderField(DateFormat::kBoundFormatIndex,
*new_bound_format_function);
// 5. Return dtf.[[BoundFormat]].
return *new_bound_format_function;
}
BUILTIN(DateTimeFormatInternalFormat) {
HandleScope scope(isolate);
Handle<Context> context = Handle<Context>(isolate->context(), isolate);
// 1. Let dtf be F.[[DateTimeFormat]].
Handle<JSObject> date_format_holder = Handle<JSObject>(
JSObject::cast(context->get(DateFormat::ContextSlot::kDateFormat)),
isolate);
// 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
// internal slot.
DCHECK(Intl::IsObjectOfType(isolate, date_format_holder,
Intl::Type::kDateTimeFormat));
Handle<Object> date = args.atOrUndefined(isolate, 1);
RETURN_RESULT_OR_FAILURE(
isolate, DateFormat::DateTimeFormat(isolate, date_format_holder, date));
}
BUILTIN(ListFormatConstructor) {
HandleScope scope(isolate);
// 1. If NewTarget is undefined, throw a TypeError exception.
......
......@@ -203,6 +203,8 @@ enum ContextLookupFlags {
V(ITERATOR_RESULT_MAP_INDEX, Map, iterator_result_map) \
V(INTL_DATE_TIME_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_date_time_format_function) \
V(INTL_DATE_FORMAT_INTERNAL_FORMAT_SHARED_FUN, SharedFunctionInfo, \
date_format_internal_format_shared_fun) \
V(INTL_NUMBER_FORMAT_FUNCTION_INDEX, JSFunction, \
intl_number_format_function) \
V(INTL_NUMBER_FORMAT_INTERNAL_FORMAT_NUMBER_SHARED_FUN, SharedFunctionInfo, \
......
......@@ -1235,20 +1235,6 @@ DEFINE_METHOD(
);
/**
* Returns a String value representing the result of calling ToNumber(date)
* according to the effective locale and the formatting options of this
* DateTimeFormat.
*/
function formatDate(formatter, dateValue) {
return %FormatDate(formatter, dateValue);
}
// Length is 1 as specified in ECMA 402 v2+
AddBoundMethod(GlobalIntlDateTimeFormat, 'format', formatDate, 1, DATE_TIME_FORMAT_TYPE,
true);
/**
* Returns canonical Area/Location(/Location) name, or throws an exception
* if the zone name is invalid IANA name.
......
......@@ -631,7 +631,8 @@ icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat(
}
icu::SimpleDateFormat* DateFormat::UnpackDateFormat(Handle<JSObject> obj) {
return reinterpret_cast<icu::SimpleDateFormat*>(obj->GetEmbedderField(0));
return reinterpret_cast<icu::SimpleDateFormat*>(
obj->GetEmbedderField(DateFormat::kSimpleDateFormatIndex));
}
void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) {
......@@ -639,6 +640,22 @@ void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) {
GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
}
MaybeHandle<JSObject> DateFormat::Unwrap(Isolate* isolate,
Handle<JSReceiver> receiver,
const char* method_name) {
Handle<Context> native_context =
Handle<Context>(isolate->context()->native_context(), isolate);
Handle<JSFunction> constructor = Handle<JSFunction>(
JSFunction::cast(native_context->intl_date_time_format_function()),
isolate);
Handle<String> method_name_str =
isolate->factory()->NewStringFromAsciiChecked(method_name);
return Intl::UnwrapReceiver(isolate, receiver, constructor,
Intl::Type::kDateTimeFormat, method_name_str,
true);
}
// ecma402/#sec-formatdatetime
// FormatDateTime( dateTimeFormat, x )
MaybeHandle<String> DateFormat::FormatDateTime(
......@@ -667,6 +684,11 @@ MaybeHandle<String> DateFormat::FormatDateTime(
MaybeHandle<String> DateFormat::DateTimeFormat(
Isolate* isolate, Handle<JSObject> date_time_format_holder,
Handle<Object> date) {
// 2. Assert: Type(dtf) is Object and dtf has an [[InitializedDateTimeFormat]]
// internal slot.
DCHECK(Intl::IsObjectOfType(isolate, date_time_format_holder,
Intl::Type::kDateTimeFormat));
// 3. If date is not provided or is undefined, then
double x;
if (date->IsUndefined()) {
......
......@@ -60,6 +60,14 @@ class DateFormat {
Isolate* isolate, Handle<JSObject> date_time_format_holder,
Handle<Object> date);
// The UnwrapDateTimeFormat abstract operation gets the underlying
// DateTimeFormat operation for various methods which implement ECMA-402 v1
// semantics for supporting initializing existing Intl objects.
//
// ecma402/#sec-unwrapdatetimeformat
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> Unwrap(
Isolate* isolate, Handle<JSReceiver> receiver, const char* method_name);
// ecma-402/#sec-todatetimeoptions
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ToDateTimeOptions(
Isolate* isolate, Handle<Object> input_options, const char* required,
......@@ -71,8 +79,28 @@ class DateFormat {
const char* service);
// Layout description.
static const int kSimpleDateFormat = JSObject::kHeaderSize;
static const int kSize = kSimpleDateFormat + kPointerSize;
#define DATE_FORMAT_FIELDS(V) \
V(kSimpleDateFormat, kPointerSize) \
V(kBoundFormat, kPointerSize) \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, DATE_FORMAT_FIELDS)
#undef DATE_FORMAT_FIELDS
// ContextSlot defines the context structure for the bound
// DateTimeFormat.prototype.format function
enum ContextSlot {
kDateFormat = Context::MIN_CONTEXT_SLOTS,
kLength
};
// TODO(ryzokuken): Remove this and use regular accessors once DateFormat is a
// subclass of JSObject
//
// This needs to be consistent with the above Layout Description
static const int kSimpleDateFormatIndex = 0;
static const int kBoundFormatIndex = 1;
private:
DateFormat();
......
......@@ -218,7 +218,8 @@ RUNTIME_FUNCTION(Runtime_CreateDateTimeFormat) {
DateFormat::InitializeDateTimeFormat(isolate, locale, options, resolved);
CHECK_NOT_NULL(date_format);
local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(date_format));
local_object->SetEmbedderField(DateFormat::kSimpleDateFormatIndex,
reinterpret_cast<Smi*>(date_format));
// Make object handle weak so we can delete the data format once GC kicks in.
Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment