Commit e04b1986 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[intl] Port receiver unwrapping logic to c++

Removes JS version and creates a runtime functions for now to
interface with existing JS uses.

Bug: v8:5751
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I150701d338a0951a5e5da1aca667c65f941850d9
Reviewed-on: https://chromium-review.googlesource.com/1122024
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54145}
parent 34c46997
......@@ -75,7 +75,10 @@ function AddBoundMethod(obj, methodName, implementation, length, type,
DEFINE_METHOD(
obj.prototype,
get [methodName]() {
var receiver = Unwrap(this, type, obj, methodName, compat);
if(!IS_RECEIVER(this)) {
throw %make_type_error(kIncompatibleMethodReceiver, methodName, this);
}
var receiver = %IntlUnwrapReceiver(this, type, obj, methodName, compat);
if (IS_UNDEFINED(receiver[internalName])) {
var boundMethod;
if (IS_UNDEFINED(length) || length === 2) {
......@@ -120,20 +123,6 @@ function IntlConstruct(receiver, constructor, create, newTarget, args,
function Unwrap(receiver, type, constructor, method, compat) {
if (!%IsInitializedIntlObjectOfType(receiver, type)) {
if (compat && receiver instanceof constructor) {
let fallback = receiver[IntlFallbackSymbol];
if (%IsInitializedIntlObjectOfType(fallback, type)) {
return fallback;
}
}
throw %make_type_error(kIncompatibleMethodReceiver, method, receiver);
}
return receiver;
}
// -------------------------------------------------------------------
/**
......@@ -1079,8 +1068,12 @@ function CollatorConstructor() {
DEFINE_METHOD(
GlobalIntlCollator.prototype,
resolvedOptions() {
var coll = Unwrap(this, COLLATOR_TYPE, GlobalIntlCollator,
'resolvedOptions', false);
var methodName = 'resolvedOptions';
if(!IS_RECEIVER(this)) {
throw %make_type_error(kIncompatibleMethodReceiver, methodName, this);
}
var coll = %IntlUnwrapReceiver(this, COLLATOR_TYPE, GlobalIntlCollator,
methodName, false);
return {
locale: coll[resolvedSymbol].locale,
usage: coll[resolvedSymbol].usage,
......@@ -1404,8 +1397,13 @@ function NumberFormatConstructor() {
DEFINE_METHOD(
GlobalIntlNumberFormat.prototype,
resolvedOptions() {
var format = Unwrap(this, NUMBER_FORMAT_TYPE, GlobalIntlNumberFormat,
'resolvedOptions', true);
var methodName = 'resolvedOptions';
if(!IS_RECEIVER(this)) {
throw %make_type_error(kIncompatibleMethodReceiver, methodName, this);
}
var format = %IntlUnwrapReceiver(this, NUMBER_FORMAT_TYPE,
GlobalIntlNumberFormat,
methodName, true);
var result = {
locale: format[resolvedSymbol].locale,
numberingSystem: format[resolvedSymbol].numberingSystem,
......@@ -1766,8 +1764,13 @@ function DateTimeFormatConstructor() {
DEFINE_METHOD(
GlobalIntlDateTimeFormat.prototype,
resolvedOptions() {
var format = Unwrap(this, DATE_TIME_FORMAT_TYPE, GlobalIntlDateTimeFormat,
'resolvedOptions', true);
var methodName = 'resolvedOptions';
if(!IS_RECEIVER(this)) {
throw %make_type_error(kIncompatibleMethodReceiver, methodName, this);
}
var format = %IntlUnwrapReceiver(this, DATE_TIME_FORMAT_TYPE,
GlobalIntlDateTimeFormat,
methodName, true);
/**
* Maps ICU calendar names to LDML/BCP47 types for key 'ca'.
......@@ -1941,8 +1944,13 @@ DEFINE_METHOD(
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
}
var segmenter = Unwrap(this, BREAK_ITERATOR_TYPE, GlobalIntlv8BreakIterator,
'resolvedOptions', false);
var methodName = 'resolvedOptions';
if(!IS_RECEIVER(this)) {
throw %make_type_error(kIncompatibleMethodReceiver, methodName, this);
}
var segmenter = %IntlUnwrapReceiver(this, BREAK_ITERATOR_TYPE,
GlobalIntlv8BreakIterator, methodName,
false);
return {
locale: segmenter[resolvedSymbol].locale,
......@@ -2012,15 +2020,15 @@ function breakType(iterator) {
AddBoundMethod(GlobalIntlv8BreakIterator, 'adoptText', adoptText, 1,
BREAK_ITERATOR_TYPE);
BREAK_ITERATOR_TYPE, false);
AddBoundMethod(GlobalIntlv8BreakIterator, 'first', first, 0,
BREAK_ITERATOR_TYPE);
BREAK_ITERATOR_TYPE, false);
AddBoundMethod(GlobalIntlv8BreakIterator, 'next', next, 0,
BREAK_ITERATOR_TYPE);
BREAK_ITERATOR_TYPE, false);
AddBoundMethod(GlobalIntlv8BreakIterator, 'current', current, 0,
BREAK_ITERATOR_TYPE);
BREAK_ITERATOR_TYPE, false);
AddBoundMethod(GlobalIntlv8BreakIterator, 'breakType', breakType, 0,
BREAK_ITERATOR_TYPE);
BREAK_ITERATOR_TYPE, false);
// Save references to Intl objects and methods we use, for added security.
var savedObjects = {
......
......@@ -1166,5 +1166,76 @@ bool Intl::IsObjectOfType(Isolate* isolate, Handle<Object> input,
return type == expected_type;
}
namespace {
// In ECMA 402 v1, Intl constructors supported a mode of operation
// where calling them with an existing object as a receiver would
// transform the receiver into the relevant Intl instance with all
// internal slots. In ECMA 402 v2, this capability was removed, to
// avoid adding internal slots on existing objects. In ECMA 402 v3,
// the capability was re-added as "normative optional" in a mode
// which chains the underlying Intl instance on any object, when the
// constructor is called
//
// See ecma402/#legacy-constructor.
MaybeHandle<Object> LegacyUnwrapReceiver(Isolate* isolate,
Handle<JSReceiver> receiver,
Handle<JSFunction> constructor,
Intl::Type type) {
bool has_initialized_slot = Intl::IsObjectOfType(isolate, receiver, type);
Handle<Object> obj_is_instance_of;
ASSIGN_RETURN_ON_EXCEPTION(isolate, obj_is_instance_of,
Object::InstanceOf(isolate, receiver, constructor),
Object);
bool is_instance_of = obj_is_instance_of->BooleanValue(isolate);
// 2. If receiver does not have an [[Initialized...]] internal slot
// and ? InstanceofOperator(receiver, constructor) is true, then
if (!has_initialized_slot && is_instance_of) {
// 2. a. Let new_receiver be ? Get(receiver, %Intl%.[[FallbackSymbol]]).
Handle<Object> new_receiver;
Handle<Symbol> marker =
handle(isolate->heap()->intl_fallback_symbol(), isolate);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, new_receiver,
JSReceiver::GetProperty(isolate, receiver, marker), Object);
return new_receiver;
}
return receiver;
}
} // namespace
MaybeHandle<JSReceiver> Intl::UnwrapReceiver(Isolate* isolate,
Handle<JSReceiver> receiver,
Handle<JSFunction> constructor,
Intl::Type type,
Handle<String> method_name,
bool check_legacy_constructor) {
Handle<Object> new_receiver = receiver;
if (check_legacy_constructor) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, new_receiver,
LegacyUnwrapReceiver(isolate, receiver, constructor, type), JSReceiver);
}
// 3. If Type(new_receiver) is not Object or nf does not have an
// [[Initialized...]] internal slot, then
if (!new_receiver->IsJSReceiver() ||
!Intl::IsObjectOfType(isolate, new_receiver, type)) {
// 3. a. Throw a TypeError exception.
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
method_name, receiver),
JSReceiver);
}
// The above IsObjectOfType returns true only for JSObjects, which
// makes this cast safe.
return Handle<JSReceiver>::cast(new_receiver);
}
} // namespace internal
} // namespace v8
......@@ -197,6 +197,15 @@ class Intl {
// script else return false and an empty string
static bool RemoveLocaleScriptTag(const std::string& icu_locale,
std::string* locale_less_script);
// Returns the underlying Intl receiver for various methods which
// implement ECMA-402 v1 semantics for supporting initializing
// existing Intl objects.
static MaybeHandle<JSReceiver> UnwrapReceiver(
Isolate* isolate, Handle<JSReceiver> receiver,
Handle<JSFunction> constructor, Intl::Type type,
Handle<String> method_name /* TODO(gsathya): Make this char const* */,
bool check_legacy_constructor = false);
};
} // namespace internal
......
......@@ -688,5 +688,20 @@ RUNTIME_FUNCTION(Runtime_DateCacheVersion) {
return date_cache_version->get(0);
}
RUNTIME_FUNCTION(Runtime_IntlUnwrapReceiver) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
CONVERT_SMI_ARG_CHECKED(type_int, 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 2);
CONVERT_ARG_HANDLE_CHECKED(String, method, 3);
CONVERT_BOOLEAN_ARG_CHECKED(check_legacy_constructor, 4);
RETURN_RESULT_OR_FAILURE(
isolate, Intl::UnwrapReceiver(isolate, receiver, constructor,
Intl::TypeFromInt(type_int), method,
check_legacy_constructor));
}
} // namespace internal
} // namespace v8
......@@ -225,6 +225,7 @@ namespace internal {
F(InternalCompare, 3, 1) \
F(InternalDateFormat, 2, 1) \
F(InternalNumberFormat, 2, 1) \
F(IntlUnwrapReceiver, 5, 1) \
F(IsInitializedIntlObjectOfType, 2, 1) \
F(MarkAsInitializedIntlObjectOfType, 2, 1) \
F(PluralRulesSelect, 2, 1) \
......
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