Commit 02914097 authored by jochen@chromium.org's avatar jochen@chromium.org

Move i18n extension's date-format C++ code to runtime

BUG=v8:2745
R=dcarney@chromium.org, mstarzinger@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16086 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 213fd4b6
......@@ -235,7 +235,6 @@ function toDateTimeOptions(options, required, defaults) {
* Useful for subclassing.
*/
function initializeDateTimeFormat(dateFormat, locales, options) {
native function NativeJSCreateDateTimeFormat();
if (dateFormat.hasOwnProperty('__initializedIntlObject')) {
throw new TypeError('Trying to re-initialize DateTimeFormat object.');
......@@ -292,7 +291,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
year: {writable: true}
});
var formatter = NativeJSCreateDateTimeFormat(
var formatter = %CreateDateTimeFormat(
requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved);
if (tz !== undefined && tz !== resolved.timeZone) {
......@@ -409,8 +408,6 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
* DateTimeFormat.
*/
function formatDate(formatter, dateValue) {
native function NativeJSInternalDateFormat();
var dateMs;
if (dateValue === undefined) {
dateMs = Date.now();
......@@ -422,7 +419,7 @@ function formatDate(formatter, dateValue) {
throw new RangeError('Provided date is not in valid range.');
}
return NativeJSInternalDateFormat(formatter.formatter, new Date(dateMs));
return %InternalDateFormat(formatter.formatter, new Date(dateMs));
}
......@@ -433,8 +430,7 @@ function formatDate(formatter, dateValue) {
* Returns undefined if date string cannot be parsed.
*/
function parseDate(formatter, value) {
native function NativeJSInternalDateParse();
return NativeJSInternalDateParse(formatter.formatter, String(value));
return %InternalDateParse(formatter.formatter, String(value));
}
......
......@@ -30,7 +30,6 @@
#include "break-iterator.h"
#include "collator.h"
#include "date-format.h"
#include "natives.h"
#include "number-format.h"
......@@ -48,15 +47,6 @@ Extension::Extension()
v8::Handle<v8::FunctionTemplate> Extension::GetNativeFunction(
v8::Handle<v8::String> name) {
// Date format and parse.
if (name->Equals(v8::String::New("NativeJSCreateDateTimeFormat"))) {
return v8::FunctionTemplate::New(DateFormat::JSCreateDateTimeFormat);
} else if (name->Equals(v8::String::New("NativeJSInternalDateFormat"))) {
return v8::FunctionTemplate::New(DateFormat::JSInternalFormat);
} else if (name->Equals(v8::String::New("NativeJSInternalDateParse"))) {
return v8::FunctionTemplate::New(DateFormat::JSInternalParse);
}
// Number format and parse.
if (name->Equals(v8::String::New("NativeJSCreateNumberFormat"))) {
return v8::FunctionTemplate::New(NumberFormat::JSCreateNumberFormat);
......
......@@ -26,11 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#include "date-format.h"
#include "i18n.h"
#include <string.h>
#include "i18n-utils.h"
#include "unicode/calendar.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
......@@ -39,195 +36,26 @@
#include "unicode/smpdtfmt.h"
#include "unicode/timezone.h"
namespace v8_i18n {
static icu::SimpleDateFormat* InitializeDateTimeFormat(v8::Handle<v8::String>,
v8::Handle<v8::Object>,
v8::Handle<v8::Object>);
static icu::SimpleDateFormat* CreateICUDateFormat(const icu::Locale&,
v8::Handle<v8::Object>);
static void SetResolvedSettings(const icu::Locale&,
icu::SimpleDateFormat*,
v8::Handle<v8::Object>);
icu::SimpleDateFormat* DateFormat::UnpackDateFormat(
v8::Handle<v8::Object> obj) {
v8::HandleScope handle_scope;
if (obj->HasOwnProperty(v8::String::New("dateFormat"))) {
return static_cast<icu::SimpleDateFormat*>(
obj->GetAlignedPointerFromInternalField(0));
}
return NULL;
}
void DateFormat::DeleteDateFormat(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
void* param) {
// First delete the hidden C++ object.
// Unpacking should never return NULL here. That would only happen if
// this method is used as the weak callback for persistent handles not
// pointing to a date time formatter.
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Object> handle = v8::Local<v8::Object>::New(isolate, *object);
delete UnpackDateFormat(handle);
// Then dispose of the persistent handle to JS object.
object->Dispose(isolate);
}
void DateFormat::JSInternalFormat(
const v8::FunctionCallbackInfo<v8::Value>& args) {
double millis = 0.0;
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsDate()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New(
"Internal error. Formatter and date value have to be specified.")));
return;
} else {
millis = v8::Date::Cast(*args[1])->NumberValue();
}
namespace v8 {
namespace internal {
icu::SimpleDateFormat* date_format = UnpackDateFormat(args[0]->ToObject());
if (!date_format) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("DateTimeFormat method called on an object "
"that is not a DateTimeFormat.")));
return;
}
namespace {
icu::UnicodeString result;
date_format->format(millis, result);
args.GetReturnValue().Set(v8::String::New(
reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length()));
}
void DateFormat::JSInternalParse(
const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::UnicodeString string_date;
if (args.Length() != 2 || !args[0]->IsObject() || !args[1]->IsString()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New(
"Internal error. Formatter and string have to be specified.")));
return;
} else {
if (!Utils::V8StringToUnicodeString(args[1], &string_date)) {
string_date = "";
}
}
icu::SimpleDateFormat* date_format = UnpackDateFormat(args[0]->ToObject());
if (!date_format) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("DateTimeFormat method called on an object "
"that is not a DateTimeFormat.")));
return;
}
UErrorCode status = U_ZERO_ERROR;
UDate date = date_format->parse(string_date, status);
if (U_FAILURE(status)) {
return;
}
args.GetReturnValue().Set(v8::Date::New(static_cast<double>(date)));
}
void DateFormat::JSCreateDateTimeFormat(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 3 ||
!args[0]->IsString() ||
!args[1]->IsObject() ||
!args[2]->IsObject()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, wrong parameters.")));
return;
}
v8::Isolate* isolate = args.GetIsolate();
v8::Local<v8::ObjectTemplate> date_format_template =
Utils::GetTemplate(isolate);
// Create an empty object wrapper.
v8::Local<v8::Object> local_object = date_format_template->NewInstance();
// But the handle shouldn't be empty.
// That can happen if there was a stack overflow when creating the object.
if (local_object.IsEmpty()) {
args.GetReturnValue().Set(local_object);
return;
}
// Set date time formatter as internal field of the resulting JS object.
icu::SimpleDateFormat* date_format = InitializeDateTimeFormat(
args[0]->ToString(), args[1]->ToObject(), args[2]->ToObject());
if (!date_format) {
v8::ThrowException(v8::Exception::Error(v8::String::New(
"Internal error. Couldn't create ICU date time formatter.")));
return;
} else {
local_object->SetAlignedPointerInInternalField(0, date_format);
v8::TryCatch try_catch;
local_object->Set(v8::String::New("dateFormat"), v8::String::New("valid"));
if (try_catch.HasCaught()) {
v8::ThrowException(v8::Exception::Error(
v8::String::New("Internal error, couldn't set property.")));
return;
}
}
v8::Persistent<v8::Object> wrapper(isolate, local_object);
// Make object handle weak so we can delete iterator once GC kicks in.
wrapper.MakeWeak<void>(NULL, &DeleteDateFormat);
args.GetReturnValue().Set(wrapper);
wrapper.ClearAndLeak();
}
static icu::SimpleDateFormat* InitializeDateTimeFormat(
v8::Handle<v8::String> locale,
v8::Handle<v8::Object> options,
v8::Handle<v8::Object> resolved) {
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
v8::String::AsciiValue bcp47_locale(locale);
if (bcp47_locale.length() != 0) {
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &status);
if (U_FAILURE(status) || icu_length == 0) {
return NULL;
}
icu_locale = icu::Locale(icu_result);
}
icu::SimpleDateFormat* date_format = CreateICUDateFormat(icu_locale, options);
if (!date_format) {
// Remove extensions and try again.
icu::Locale no_extension_locale(icu_locale.getBaseName());
date_format = CreateICUDateFormat(no_extension_locale, options);
// Set resolved settings (pattern, numbering system, calendar).
SetResolvedSettings(no_extension_locale, date_format, resolved);
} else {
SetResolvedSettings(icu_locale, date_format, resolved);
}
return date_format;
}
static icu::SimpleDateFormat* CreateICUDateFormat(
const icu::Locale& icu_locale, v8::Handle<v8::Object> options) {
icu::SimpleDateFormat* CreateICUDateFormat(
Isolate* isolate,
const icu::Locale& icu_locale,
Handle<Object> options) {
// Create time zone as specified by the user. We have to re-create time zone
// since calendar takes ownership.
icu::TimeZone* tz = NULL;
icu::UnicodeString timezone;
if (Utils::ExtractStringSetting(options, "timeZone", &timezone)) {
tz = icu::TimeZone::createTimeZone(timezone);
MaybeObject* maybe_object = options->GetProperty(
*isolate->factory()->NewStringFromAscii(CStrVector("timeZone")));
Object* timezone;
if (maybe_object->ToObject(&timezone) && timezone->IsString()) {
v8::String::Utf8Value utf8_timezone(
v8::Utils::ToLocal(Handle<String>(String::cast(timezone))));
icu::UnicodeString u_timezone(icu::UnicodeString::fromUTF8(*utf8_timezone));
tz = icu::TimeZone::createTimeZone(u_timezone);
} else {
tz = icu::TimeZone::createDefault();
}
......@@ -240,13 +68,18 @@ static icu::SimpleDateFormat* CreateICUDateFormat(
// Make formatter from skeleton. Calendar and numbering system are added
// to the locale as Unicode extension (if they were specified at all).
icu::SimpleDateFormat* date_format = NULL;
icu::UnicodeString skeleton;
if (Utils::ExtractStringSetting(options, "skeleton", &skeleton)) {
Object* skeleton;
maybe_object = options->GetProperty(
*isolate->factory()->NewStringFromAscii(CStrVector("skeleton")));
if (maybe_object->ToObject(&skeleton) && skeleton->IsString()) {
v8::String::Utf8Value utf8_skeleton(
v8::Utils::ToLocal(Handle<String>(String::cast(skeleton))));
icu::UnicodeString u_skeleton(icu::UnicodeString::fromUTF8(*utf8_skeleton));
icu::DateTimePatternGenerator* generator =
icu::DateTimePatternGenerator::createInstance(icu_locale, status);
icu::UnicodeString pattern;
if (U_SUCCESS(status)) {
pattern = generator->getBestPattern(skeleton, status);
pattern = generator->getBestPattern(u_skeleton, status);
delete generator;
}
......@@ -265,37 +98,59 @@ static icu::SimpleDateFormat* CreateICUDateFormat(
return date_format;
}
static void SetResolvedSettings(const icu::Locale& icu_locale,
icu::SimpleDateFormat* date_format,
v8::Handle<v8::Object> resolved) {
void SetResolvedSettings(Isolate* isolate,
const icu::Locale& icu_locale,
icu::SimpleDateFormat* date_format,
Handle<JSObject> resolved) {
UErrorCode status = U_ZERO_ERROR;
icu::UnicodeString pattern;
date_format->toPattern(pattern);
resolved->Set(v8::String::New("pattern"),
v8::String::New(reinterpret_cast<const uint16_t*>(
pattern.getBuffer()), pattern.length()));
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("pattern")),
isolate->factory()->NewStringFromTwoByte(
Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
pattern.length())),
NONE,
kNonStrictMode);
// Set time zone and calendar.
if (date_format) {
const icu::Calendar* calendar = date_format->getCalendar();
const char* calendar_name = calendar->getType();
resolved->Set(v8::String::New("calendar"), v8::String::New(calendar_name));
const icu::TimeZone& tz = calendar->getTimeZone();
icu::UnicodeString time_zone;
tz.getID(time_zone);
icu::UnicodeString canonical_time_zone;
icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
if (U_SUCCESS(status)) {
if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
resolved->Set(v8::String::New("timeZone"), v8::String::New("UTC"));
} else {
resolved->Set(v8::String::New("timeZone"),
v8::String::New(reinterpret_cast<const uint16_t*>(
canonical_time_zone.getBuffer()),
canonical_time_zone.length()));
}
const icu::Calendar* calendar = date_format->getCalendar();
const char* calendar_name = calendar->getType();
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("calendar")),
isolate->factory()->NewStringFromAscii(CStrVector(calendar_name)),
NONE,
kNonStrictMode);
const icu::TimeZone& tz = calendar->getTimeZone();
icu::UnicodeString time_zone;
tz.getID(time_zone);
icu::UnicodeString canonical_time_zone;
icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
if (U_SUCCESS(status)) {
if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("timeZone")),
isolate->factory()->NewStringFromAscii(CStrVector("UTC")),
NONE,
kNonStrictMode);
} else {
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("timeZone")),
isolate->factory()->NewStringFromTwoByte(
Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(
canonical_time_zone.getBuffer()),
canonical_time_zone.length())),
NONE,
kNonStrictMode);
}
}
......@@ -307,9 +162,19 @@ static void SetResolvedSettings(const icu::Locale& icu_locale,
icu::NumberingSystem::createInstance(icu_locale, status);
if (U_SUCCESS(status)) {
const char* ns = numbering_system->getName();
resolved->Set(v8::String::New("numberingSystem"), v8::String::New(ns));
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
isolate->factory()->NewStringFromAscii(CStrVector(ns)),
NONE,
kNonStrictMode);
} else {
resolved->Set(v8::String::New("numberingSystem"), v8::Undefined());
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")),
isolate->factory()->undefined_value(),
NONE,
kNonStrictMode);
}
delete numbering_system;
......@@ -319,11 +184,114 @@ static void SetResolvedSettings(const icu::Locale& icu_locale,
uloc_toLanguageTag(
icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status);
if (U_SUCCESS(status)) {
resolved->Set(v8::String::New("locale"), v8::String::New(result));
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("locale")),
isolate->factory()->NewStringFromAscii(CStrVector(result)),
NONE,
kNonStrictMode);
} else {
// This would never happen, since we got the locale from ICU.
resolved->Set(v8::String::New("locale"), v8::String::New("und"));
JSObject::SetProperty(
resolved,
isolate->factory()->NewStringFromAscii(CStrVector("locale")),
isolate->factory()->NewStringFromAscii(CStrVector("und")),
NONE,
kNonStrictMode);
}
}
template<int internal_fields, EternalHandles::SingletonHandle field>
Handle<ObjectTemplateInfo> GetEternal(Isolate* isolate) {
if (isolate->eternal_handles()->Exists(field)) {
return Handle<ObjectTemplateInfo>::cast(
isolate->eternal_handles()->GetSingleton(field));
}
v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New());
raw_template->SetInternalFieldCount(internal_fields);
return Handle<ObjectTemplateInfo>::cast(
isolate->eternal_handles()->CreateSingleton(
isolate,
*v8::Utils::OpenHandle(*raw_template),
field));
}
} // namespace
// static
Handle<ObjectTemplateInfo> I18N::GetTemplate(Isolate* isolate) {
return GetEternal<1, i::EternalHandles::I18N_TEMPLATE_ONE>(isolate);
}
// static
Handle<ObjectTemplateInfo> I18N::GetTemplate2(Isolate* isolate) {
return GetEternal<2, i::EternalHandles::I18N_TEMPLATE_TWO>(isolate);
}
// static
icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat(
Isolate* isolate,
Handle<String> locale,
Handle<JSObject> options,
Handle<JSObject> resolved) {
// Convert BCP47 into ICU locale format.
UErrorCode status = U_ZERO_ERROR;
icu::Locale icu_locale;
char icu_result[ULOC_FULLNAME_CAPACITY];
int icu_length = 0;
v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale));
if (bcp47_locale.length() != 0) {
uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
&icu_length, &status);
if (U_FAILURE(status) || icu_length == 0) {
return NULL;
}
icu_locale = icu::Locale(icu_result);
}
icu::SimpleDateFormat* date_format = CreateICUDateFormat(
isolate, icu_locale, options);
if (!date_format) {
// Remove extensions and try again.
icu::Locale no_extension_locale(icu_locale.getBaseName());
date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
// Set resolved settings (pattern, numbering system, calendar).
SetResolvedSettings(isolate, no_extension_locale, date_format, resolved);
} else {
SetResolvedSettings(isolate, icu_locale, date_format, resolved);
}
return date_format;
}
icu::SimpleDateFormat* DateFormat::UnpackDateFormat(
Isolate* isolate,
Handle<JSObject> obj) {
if (obj->HasLocalProperty(
*isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")))) {
return reinterpret_cast<icu::SimpleDateFormat*>(
obj->GetInternalField(0));
}
return NULL;
}
void DateFormat::DeleteDateFormat(v8::Isolate* isolate,
Persistent<v8::Object>* object,
void* param) {
// First delete the hidden C++ object.
delete reinterpret_cast<icu::SimpleDateFormat*>(Handle<JSObject>::cast(
v8::Utils::OpenPersistent(object))->GetInternalField(0));
// Then dispose of the persistent handle to JS object.
object->Dispose(isolate);
}
} // namespace v8_i18n
} } // namespace v8::internal
......@@ -26,8 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// limitations under the License.
#ifndef V8_EXTENSIONS_I18N_DATE_FORMAT_H_
#define V8_EXTENSIONS_I18N_DATE_FORMAT_H_
#ifndef V8_I18N_H_
#define V8_I18N_H_
#include "unicode/uversion.h"
#include "v8.h"
......@@ -36,36 +36,44 @@ namespace U_ICU_NAMESPACE {
class SimpleDateFormat;
}
namespace v8_i18n {
namespace v8 {
namespace internal {
class DateFormat {
class I18N {
public:
static void JSCreateDateTimeFormat(
const v8::FunctionCallbackInfo<v8::Value>& args);
// Creates an ObjectTemplate with one internal field.
static Handle<ObjectTemplateInfo> GetTemplate(Isolate* isolate);
// Creates an ObjectTemplate with two internal fields.
static Handle<ObjectTemplateInfo> GetTemplate2(Isolate* isolate);
private:
I18N();
};
// Helper methods for various bindings.
class DateFormat {
public:
// Create a formatter for the specificied locale and options. Returns the
// resolved settings for the locale / options.
static icu::SimpleDateFormat* InitializeDateTimeFormat(
Isolate* isolate,
Handle<String> locale,
Handle<JSObject> options,
Handle<JSObject> resolved);
// Unpacks date format object from corresponding JavaScript object.
static icu::SimpleDateFormat* UnpackDateFormat(
v8::Handle<v8::Object> obj);
static icu::SimpleDateFormat* UnpackDateFormat(Isolate* isolate,
Handle<JSObject> obj);
// Release memory we allocated for the DateFormat once the JS object that
// holds the pointer gets garbage collected.
static void DeleteDateFormat(v8::Isolate* isolate,
v8::Persistent<v8::Object>* object,
Persistent<v8::Object>* object,
void* param);
// Formats date and returns corresponding string.
static void JSInternalFormat(const v8::FunctionCallbackInfo<v8::Value>& args);
// Parses date and returns corresponding Date object or undefined if parse
// failed.
static void JSInternalParse(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
DateFormat();
};
} // namespace v8_i18n
} } // namespace v8::internal
#endif // V8_EXTENSIONS_I18N_DATE_FORMAT_H_
#endif // V8_I18N_H_
......@@ -67,10 +67,18 @@
#include "vm-state-inl.h"
#ifdef V8_I18N_SUPPORT
#include "i18n.h"
#include "unicode/brkiter.h"
#include "unicode/calendar.h"
#include "unicode/coll.h"
#include "unicode/datefmt.h"
#include "unicode/dtfmtsym.h"
#include "unicode/dtptngen.h"
#include "unicode/locid.h"
#include "unicode/numfmt.h"
#include "unicode/numsys.h"
#include "unicode/smpdtfmt.h"
#include "unicode/timezone.h"
#include "unicode/uloc.h"
#include "unicode/uversion.h"
#endif
......@@ -13553,6 +13561,110 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
result->set_length(Smi::FromInt(length));
return *result;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
Handle<ObjectTemplateInfo> date_format_template =
I18N::GetTemplate(isolate);
// Create an empty object wrapper.
bool has_pending_exception = false;
Handle<JSObject> local_object = Execution::InstantiateObject(
date_format_template, &has_pending_exception);
if (has_pending_exception) {
ASSERT(isolate->has_pending_exception());
return Failure::Exception();
}
// Set date time formatter as internal field of the resulting JS object.
icu::SimpleDateFormat* date_format = DateFormat::InitializeDateTimeFormat(
isolate, locale, options, resolved);
if (!date_format) return isolate->ThrowIllegalOperation();
local_object->SetInternalField(0, reinterpret_cast<Smi*>(date_format));
RETURN_IF_EMPTY_HANDLE(isolate,
JSObject::SetLocalPropertyIgnoreAttributes(
local_object,
isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")),
isolate->factory()->NewStringFromAscii(CStrVector("valid")),
NONE));
Persistent<v8::Object> wrapper(reinterpret_cast<v8::Isolate*>(isolate),
v8::Utils::ToLocal(local_object));
// Make object handle weak so we can delete the data format once GC kicks in.
wrapper.MakeWeak<void>(NULL, &DateFormat::DeleteDateFormat);
Handle<Object> result = Utils::OpenPersistent(wrapper);
wrapper.ClearAndLeak();
return *result;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateFormat) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 1);
bool has_pending_exception = false;
double millis = Execution::ToNumber(date, &has_pending_exception)->Number();
if (has_pending_exception) {
ASSERT(isolate->has_pending_exception());
return Failure::Exception();
}
icu::SimpleDateFormat* date_format =
DateFormat::UnpackDateFormat(isolate, date_format_holder);
if (!date_format) return isolate->ThrowIllegalOperation();
icu::UnicodeString result;
date_format->format(millis, result);
return *isolate->factory()->NewStringFromTwoByte(
Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(result.getBuffer()),
result.length()));
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_InternalDateParse) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, date_format_holder, 0);
CONVERT_ARG_HANDLE_CHECKED(String, date_string, 1);
v8::String::Utf8Value utf8_date(v8::Utils::ToLocal(date_string));
icu::UnicodeString u_date(icu::UnicodeString::fromUTF8(*utf8_date));
icu::SimpleDateFormat* date_format =
DateFormat::UnpackDateFormat(isolate, date_format_holder);
if (!date_format) return isolate->ThrowIllegalOperation();
UErrorCode status = U_ZERO_ERROR;
UDate date = date_format->parse(u_date, status);
if (U_FAILURE(status)) return isolate->heap()->undefined_value();
bool has_pending_exception = false;
Handle<JSDate> result = Handle<JSDate>::cast(
Execution::NewDate(static_cast<double>(date), &has_pending_exception));
if (has_pending_exception) {
ASSERT(isolate->has_pending_exception());
return Failure::Exception();
}
return *result;
}
#endif // V8_I18N_SUPPORT
......
......@@ -543,6 +543,11 @@ namespace internal {
F(AvailableLocalesOf, 1, 1) \
F(GetDefaultICULocale, 0, 1) \
F(GetLanguageTagVariants, 1, 1) \
\
/* Date format and parse. */ \
F(CreateDateTimeFormat, 3, 1) \
F(InternalDateFormat, 2, 1) \
F(InternalDateParse, 2, 1) \
#else
#define RUNTIME_FUNCTION_LIST_I18N_SUPPORT(F)
......
......@@ -823,12 +823,12 @@
}],
['v8_enable_i18n_support==1', {
'sources': [
'../../src/i18n.cc',
'../../src/i18n.h',
'../../src/extensions/i18n/break-iterator.cc',
'../../src/extensions/i18n/break-iterator.h',
'../../src/extensions/i18n/collator.cc',
'../../src/extensions/i18n/collator.h',
'../../src/extensions/i18n/date-format.cc',
'../../src/extensions/i18n/date-format.h',
'../../src/extensions/i18n/i18n-extension.cc',
'../../src/extensions/i18n/i18n-extension.h',
'../../src/extensions/i18n/i18n-utils.cc',
......
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