Commit 3834c637 authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[torque] Stricter object field verification, part 1

This change adjusts object initialization order for a few classes so
that the GC can never see those objects in an invalid, partially-
initialized state.

AccessorInfo: Just zeros out a few fields upon construction. This is the
simplest case.

FunctionTemplateInfo: Slightly changes the order in which fields are
set, so that the Smi field is set ahead of the call to SetCallHandler,
which can GC. Also a pretty simple case.

JSListFormat, JSPluralRules, JSRelativeTimeFormat, JSSegmenter: The spec
requires that we start with OrdinaryCreateFromConstructor, which has
observable side effects (it fetches the prototype from the new.target).
So we split JSObject::New in half: the first half does all of the user-
visible things and returns a Map, which we can pass to the second half
when we're ready to actually allocate the object.

JSTypedArray: Extends the pattern from JSListFormat into Torque code:
start with a Map and don't allocate the object until we're ready to set
all of its properties.

Bug: v8:9311
Change-Id: Id7703e8a0727ec756c774cfbb56af787658a111a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1646844
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62123}
parent 2f2657a6
......@@ -1434,17 +1434,21 @@ static Local<FunctionTemplate> FunctionTemplateNew(
i::FUNCTION_TEMPLATE_INFO_TYPE, i::AllocationType::kOld);
i::Handle<i::FunctionTemplateInfo> obj =
i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
InitializeFunctionTemplate(obj);
obj->set_do_not_cache(do_not_cache);
int next_serial_number = i::FunctionTemplateInfo::kInvalidSerialNumber;
if (!do_not_cache) {
next_serial_number = isolate->heap()->GetNextTemplateSerialNumber();
{
// Disallow GC until all fields of obj have acceptable types.
i::DisallowHeapAllocation no_gc;
InitializeFunctionTemplate(obj);
obj->set_length(length);
obj->set_do_not_cache(do_not_cache);
int next_serial_number = i::FunctionTemplateInfo::kInvalidSerialNumber;
if (!do_not_cache) {
next_serial_number = isolate->heap()->GetNextTemplateSerialNumber();
}
obj->set_serial_number(i::Smi::FromInt(next_serial_number));
}
obj->set_serial_number(i::Smi::FromInt(next_serial_number));
if (callback != nullptr) {
Utils::ToLocal(obj)->SetCallHandler(callback, data, side_effect_type);
}
obj->set_length(length);
obj->set_undetectable(false);
obj->set_needs_access_check(false);
obj->set_accept_any_receiver(true);
......
......@@ -317,6 +317,16 @@ macro GetDerivedMap(implicit context: Context)(
}
}
macro AllocateFastOrSlowJSObjectFromMap(implicit context: Context)(map: Map):
JSObject {
let properties = kEmptyFixedArray;
if (IsDictionaryMap(map)) {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
return AllocateJSObjectFromMap(
map, properties, kEmptyFixedArray, kNone, kWithSlackTracking);
}
extern class JSFunction extends JSObject {
shared_function_info: SharedFunctionInfo;
context: Context;
......@@ -633,30 +643,6 @@ extern class JSArrayBufferView extends JSObject {
}
extern class JSTypedArray extends JSArrayBufferView {
AttachOffHeapBuffer(buffer: JSArrayBuffer, byteOffset: uintptr): void {
const basePointer: Smi = 0;
// The max byteOffset is 8 * MaxSmi on the particular platform. 32 bit
// platforms are self-limiting, because we can't allocate an array bigger
// than our 32-bit arithmetic range anyway. 64 bit platforms could
// theoretically have an offset up to 2^35 - 1.
const backingStore = buffer.backing_store;
const externalPointer = backingStore + Convert<intptr>(byteOffset);
// Assert no overflow has occurred. Only assert if the mock array buffer
// allocator is NOT used. When the mock array buffer is used, impossibly
// large allocations are allowed that would erroneously cause an overflow
// and this assertion to fail.
assert(
IsMockArrayBufferAllocatorFlag() ||
Convert<uintptr>(externalPointer) >= Convert<uintptr>(backingStore));
this.elements = kEmptyByteArray;
this.buffer = buffer;
this.external_pointer = externalPointer;
this.base_pointer = basePointer;
}
length: uintptr;
external_pointer: RawPtr;
base_pointer: ByteArray | Smi;
......@@ -729,7 +715,7 @@ extern class FunctionTemplateInfo extends TemplateInfo {
function_template_rare_data: Object;
shared_function_info: Object;
flag: Smi;
@noVerifier length: Smi;
length: Smi;
cached_property_name: Object;
}
......@@ -964,9 +950,9 @@ const kAllowLargeObjectAllocation: constexpr AllocationFlags
generates 'CodeStubAssembler::kAllowLargeObjectAllocation';
const kWithSlackTracking: constexpr SlackTrackingMode
generates 'SlackTrackingMode::kWithSlackTracking';
generates 'CodeStubAssembler::SlackTrackingMode::kWithSlackTracking';
const kNoSlackTracking: constexpr SlackTrackingMode
generates 'SlackTrackingMode::kNoSlackTracking';
generates 'CodeStubAssembler::SlackTrackingMode::kNoSlackTracking';
const kFixedDoubleArrays: constexpr ExtractFixedArrayFlags
generates 'CodeStubAssembler::ExtractFixedArrayFlag::kFixedDoubleArrays';
......@@ -1075,6 +1061,12 @@ const kStrictReadOnlyProperty: constexpr MessageTemplate
const kString: constexpr PrimitiveType
generates 'PrimitiveType::kString';
const kExternalPointerForOnHeapArray: constexpr RawPtr
generates 'JSTypedArray::ExternalPointerForOnHeapArray()';
const kNameDictionaryInitialCapacity:
constexpr int32 generates 'NameDictionary::kInitialCapacity';
type Hole extends Oddball;
type Null extends Oddball;
type Undefined extends Oddball;
......@@ -1237,9 +1229,9 @@ extern class AccessorInfo extends Struct {
name: Object;
flags: Smi;
expected_receiver_type: Object;
@noVerifier setter: Foreign | Zero;
@noVerifier getter: Foreign | Zero;
@noVerifier js_getter: Foreign | Zero;
setter: Foreign | Zero;
getter: Foreign | Zero;
js_getter: Foreign | Zero;
data: Object;
}
......@@ -1446,6 +1438,10 @@ extern macro ConstructWithTarget(implicit context: Context)(
extern macro SpeciesConstructor(implicit context: Context)(
Object, JSReceiver): JSReceiver;
extern macro ConstructorBuiltinsAssembler::IsDictionaryMap(Map): bool;
extern macro CodeStubAssembler::AllocateNameDictionary(constexpr int32):
NameDictionary;
extern builtin ToObject(Context, Object): JSReceiver;
extern macro ToObject_Inline(Context, Object): JSReceiver;
extern macro IsNullOrUndefined(Object): bool;
......@@ -2062,6 +2058,7 @@ extern macro Int32Constant(constexpr ElementsKind): ElementsKind;
extern macro IntPtrConstant(constexpr NativeContextSlot): NativeContextSlot;
extern macro IntPtrConstant(constexpr ContextSlot): ContextSlot;
extern macro IntPtrConstant(constexpr intptr): intptr;
extern macro PointerConstant(constexpr RawPtr): RawPtr;
extern macro SingleCharacterStringConstant(constexpr string): String;
extern macro BitcastWordToTaggedSigned(intptr): Smi;
......
......@@ -3,13 +3,6 @@
// found in the LICENSE file.
namespace boolean {
const kNameDictionaryInitialCapacity:
constexpr int32 generates 'NameDictionary::kInitialCapacity';
extern macro ConstructorBuiltinsAssembler::IsDictionaryMap(Map): bool;
extern macro CodeStubAssembler::AllocateNameDictionary(constexpr int32):
NameDictionary;
// TODO(v8:9120): This is a workaround to get access to target and new.target
// in javascript builtins. Requires cleanup once this is fully supported by
// torque.
......@@ -29,13 +22,8 @@ namespace boolean {
const target = UnsafeCast<JSFunction>(Parameter(TARGET_INDEX));
const map = GetDerivedMap(target, UnsafeCast<JSReceiver>(newTarget));
let properties = kEmptyFixedArray;
if (IsDictionaryMap(map)) {
properties = AllocateNameDictionary(kNameDictionaryInitialCapacity);
}
const obj = UnsafeCast<JSValue>(AllocateJSObjectFromMap(
map, properties, kEmptyFixedArray, kNone, kWithSlackTracking));
const obj = UnsafeCast<JSValue>(AllocateFastOrSlowJSObjectFromMap(map));
obj.value = value;
return obj;
}
......
......@@ -351,21 +351,17 @@ Object DisallowCallConstructor(BuiltinArguments args, Isolate* isolate,
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<JSObject> obj;
Handle<Map> map;
// 2. Let result be OrdinaryCreateFromConstructor(NewTarget,
// "%<T>Prototype%").
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, obj,
JSObject::New(target, new_target, Handle<AllocationSite>::null()));
Handle<T> result = Handle<T>::cast(obj);
result->set_flags(0);
isolate, map, JSFunction::GetDerivedMap(isolate, target, new_target));
Handle<Object> locales = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
// 3. Return Initialize<T>(t, locales, options).
RETURN_RESULT_OR_FAILURE(isolate,
T::Initialize(isolate, result, locales, options));
// 3. Return New<T>(t, locales, options).
RETURN_RESULT_OR_FAILURE(isolate, T::New(isolate, map, locales, options));
}
/**
......
......@@ -27,23 +27,9 @@ using TNode = compiler::TNode<T>;
// -----------------------------------------------------------------------------
// ES6 section 22.2 TypedArray Objects
// Setup the TypedArray which is under construction.
// - Set the length.
// - Set the byte_offset.
// - Set the byte_length.
// - Set EmbedderFields to 0.
void TypedArrayBuiltinsAssembler::SetupTypedArray(TNode<JSTypedArray> holder,
TNode<UintPtrT> length,
TNode<UintPtrT> byte_offset,
TNode<UintPtrT> byte_length) {
StoreObjectFieldNoWriteBarrier(holder, JSTypedArray::kLengthOffset, length,
MachineType::PointerRepresentation());
StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteOffsetOffset,
byte_offset,
MachineType::PointerRepresentation());
StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteLengthOffset,
byte_length,
MachineType::PointerRepresentation());
// Sets the embedder fields to 0 for a TypedArray which is under construction.
void TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields(
TNode<JSTypedArray> holder) {
for (int offset = JSTypedArray::kHeaderSize;
offset < JSTypedArray::kSizeWithEmbedderFields; offset += kTaggedSize) {
StoreObjectField(holder, offset, SmiConstant(0));
......@@ -54,8 +40,7 @@ void TypedArrayBuiltinsAssembler::SetupTypedArray(TNode<JSTypedArray> holder,
// elements.
// TODO(bmeurer,v8:4153): Rename this and maybe fix up the implementation a bit.
TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
TNode<Context> context, TNode<JSTypedArray> holder,
TNode<UintPtrT> byte_length) {
TNode<Context> context, TNode<UintPtrT> byte_length) {
TNode<Context> native_context = LoadNativeContext(context);
TNode<Map> map =
CAST(LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX));
......@@ -97,16 +82,6 @@ TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
}
StoreObjectField(holder, JSTypedArray::kBufferOffset, buffer);
TNode<ByteArray> elements = AllocateByteArray(byte_length);
StoreObjectField(holder, JSTypedArray::kElementsOffset, elements);
StoreObjectField(holder, JSTypedArray::kBasePointerOffset, elements);
StoreObjectFieldNoWriteBarrier(
holder, JSTypedArray::kExternalPointerOffset,
PointerConstant(JSTypedArray::ExternalPointerForOnHeapArray()),
MachineType::PointerRepresentation());
return buffer;
}
......@@ -228,7 +203,12 @@ TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
TorqueStructTypedArrayElementsInfo
TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
TNode<JSTypedArray> typed_array) {
TNode<Int32T> elements_kind = LoadElementsKind(typed_array);
return GetTypedArrayElementsInfo(LoadMap(typed_array));
}
TorqueStructTypedArrayElementsInfo
TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(TNode<Map> map) {
TNode<Int32T> elements_kind = LoadMapElementsKind(map);
TVARIABLE(UintPtrT, var_size_log2);
TVARIABLE(Map, var_map);
ReadOnlyRoots roots(isolate());
......
......@@ -27,15 +27,12 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
const char* method_name,
IterationKind iteration_kind);
void SetupTypedArray(TNode<JSTypedArray> holder, TNode<UintPtrT> length,
TNode<UintPtrT> byte_offset,
TNode<UintPtrT> byte_length);
void SetupTypedArrayEmbedderFields(TNode<JSTypedArray> holder);
void AttachBuffer(TNode<JSTypedArray> holder, TNode<JSArrayBuffer> buffer,
TNode<Map> map, TNode<Smi> length,
TNode<UintPtrT> byte_offset);
TNode<JSArrayBuffer> AllocateEmptyOnHeapBuffer(TNode<Context> context,
TNode<JSTypedArray> holder,
TNode<UintPtrT> byte_length);
TNode<Map> LoadMapForType(TNode<JSTypedArray> array);
......@@ -54,6 +51,7 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
// Returns information (byte size and map) about a TypedArray's elements.
ElementsInfo GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array);
ElementsInfo GetTypedArrayElementsInfo(TNode<Map> map);
TNode<JSFunction> GetDefaultConstructor(TNode<Context> context,
TNode<JSTypedArray> exemplar);
......
......@@ -65,6 +65,8 @@ namespace typed_array {
implicit context: Context)(JSTypedArray): JSArrayBuffer;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
JSTypedArray): TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(Map):
TypedArrayElementsInfo;
extern macro TypedArrayBuiltinsAssembler::IsBigInt64ElementsKind(
ElementsKind): bool;
extern macro LoadFixedTypedArrayElementAsTagged(
......
......@@ -1536,6 +1536,7 @@ void JSArrayBuffer::JSArrayBufferVerify(Isolate* isolate) {
void JSArrayBufferView::JSArrayBufferViewVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSArrayBufferViewVerify(*this, isolate);
CHECK(buffer().IsJSArrayBuffer());
CHECK_LE(byte_length(), JSArrayBuffer::kMaxByteLength);
CHECK_LE(byte_offset(), JSArrayBuffer::kMaxByteLength);
}
......@@ -1873,6 +1874,8 @@ void JSDateTimeFormat::JSDateTimeFormatVerify(Isolate* isolate) {
void JSListFormat::JSListFormatVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSListFormatVerify(*this, isolate);
CHECK(locale().IsString());
CHECK(icu_formatter().IsForeign());
VerifySmiField(kFlagsOffset);
}
......@@ -1885,11 +1888,16 @@ void JSNumberFormat::JSNumberFormatVerify(Isolate* isolate) {
void JSPluralRules::JSPluralRulesVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSPluralRulesVerify(*this, isolate);
CHECK(locale().IsString());
VerifySmiField(kFlagsOffset);
CHECK(icu_plural_rules().IsForeign());
CHECK(icu_number_formatter().IsForeign());
}
void JSRelativeTimeFormat::JSRelativeTimeFormatVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSRelativeTimeFormatVerify(*this, isolate);
CHECK(locale().IsString());
CHECK(icu_formatter().IsForeign());
VerifySmiField(kFlagsOffset);
}
......@@ -1900,6 +1908,8 @@ void JSSegmentIterator::JSSegmentIteratorVerify(Isolate* isolate) {
void JSSegmenter::JSSegmenterVerify(Isolate* isolate) {
TorqueGeneratedClassVerifiers::JSSegmenterVerify(*this, isolate);
CHECK(locale().IsString());
CHECK(icu_break_iterator().IsForeign());
VerifySmiField(kFlagsOffset);
}
......
......@@ -104,6 +104,15 @@ Handle<JSArray> Factory::NewJSArrayWithElements(Handle<FixedArrayBase> elements,
allocation);
}
Handle<JSObject> Factory::NewFastOrSlowJSObjectFromMap(
Handle<Map> map, int number_of_slow_properties, AllocationType allocation,
Handle<AllocationSite> allocation_site) {
return map->is_dictionary_map()
? NewSlowJSObjectFromMap(map, number_of_slow_properties,
allocation, allocation_site)
: NewJSObjectFromMap(map, allocation, allocation_site);
}
Handle<Object> Factory::NewURIError() {
return NewError(isolate()->uri_error_function(),
MessageTemplate::kURIMalformed);
......
......@@ -1640,10 +1640,17 @@ Handle<AliasedArgumentsEntry> Factory::NewAliasedArgumentsEntry(
Handle<AccessorInfo> Factory::NewAccessorInfo() {
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(
NewStruct(ACCESSOR_INFO_TYPE, AllocationType::kOld));
DisallowHeapAllocation no_gc;
info->set_name(*empty_string());
info->set_flags(0); // Must clear the flags, it was initialized as undefined.
info->set_is_sloppy(true);
info->set_initial_property_attributes(NONE);
// Clear some other fields that should not be undefined.
info->set_getter(Smi::kZero);
info->set_setter(Smi::kZero);
info->set_js_getter(Smi::kZero);
return info;
}
......@@ -2886,12 +2893,14 @@ Handle<JSObject> Factory::NewJSObjectFromMap(
return js_obj;
}
Handle<JSObject> Factory::NewSlowJSObjectFromMap(Handle<Map> map, int capacity,
AllocationType allocation) {
Handle<JSObject> Factory::NewSlowJSObjectFromMap(
Handle<Map> map, int capacity, AllocationType allocation,
Handle<AllocationSite> allocation_site) {
DCHECK(map->is_dictionary_map());
Handle<NameDictionary> object_properties =
NameDictionary::New(isolate(), capacity);
Handle<JSObject> js_object = NewJSObjectFromMap(map, allocation);
Handle<JSObject> js_object =
NewJSObjectFromMap(map, allocation, allocation_site);
js_object->set_raw_properties_or_hash(*object_properties);
return js_object;
}
......
......@@ -625,10 +625,19 @@ class V8_EXPORT_PRIVATE Factory {
Handle<JSObject> NewJSObjectFromMap(
Handle<Map> map, AllocationType allocation = AllocationType::kYoung,
Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
// Like NewJSObjectFromMap, but includes allocating a properties dictionary.
Handle<JSObject> NewSlowJSObjectFromMap(
Handle<Map> map,
int number_of_slow_properties = NameDictionary::kInitialCapacity,
AllocationType allocation = AllocationType::kYoung);
AllocationType allocation = AllocationType::kYoung,
Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
// Calls NewJSObjectFromMap or NewSlowJSObjectFromMap depending on whether the
// map is a dictionary map.
inline Handle<JSObject> NewFastOrSlowJSObjectFromMap(
Handle<Map> map,
int number_of_slow_properties = NameDictionary::kInitialCapacity,
AllocationType allocation = AllocationType::kYoung,
Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
// Allocates and initializes a new JavaScript object with the given
// {prototype} and {properties}. The newly created object will be
// in dictionary properties mode. The {elements} can either be the
......
......@@ -114,11 +114,9 @@ JSListFormat::Type get_type(const char* str) {
UNREACHABLE();
}
MaybeHandle<JSListFormat> JSListFormat::Initialize(
Isolate* isolate, Handle<JSListFormat> list_format, Handle<Object> locales,
Handle<Object> input_options) {
list_format->set_flags(0);
MaybeHandle<JSListFormat> JSListFormat::New(Isolate* isolate, Handle<Map> map,
Handle<Object> locales,
Handle<Object> input_options) {
Handle<JSReceiver> options;
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> maybe_requested_locales =
......@@ -156,11 +154,8 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize(
Intl::ResolvedLocale r =
Intl::ResolveLocale(isolate, JSListFormat::GetAvailableLocales(),
requested_locales, matcher, {});
// 11. Set listFormat.[[Locale]] to r.[[Locale]].
Handle<String> locale_str =
isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str());
list_format->set_locale(*locale_str);
// 12. Let t be GetOption(options, "type", "string", «"conjunction",
// "disjunction", "unit"», "conjunction").
......@@ -171,9 +166,6 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize(
MAYBE_RETURN(maybe_type, MaybeHandle<JSListFormat>());
Type type_enum = maybe_type.FromJust();
// 13. Set listFormat.[[Type]] to t.
list_format->set_type(type_enum);
// 14. Let s be ? GetOption(options, "style", "string",
// «"long", "short", "narrow"», "long").
Maybe<Style> maybe_style = Intl::GetStringOption<Style>(
......@@ -182,9 +174,6 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize(
MAYBE_RETURN(maybe_style, MaybeHandle<JSListFormat>());
Style style_enum = maybe_style.FromJust();
// 15. Set listFormat.[[Style]] to s.
list_format->set_style(style_enum);
icu::Locale icu_locale = r.icu_locale;
UErrorCode status = U_ZERO_ERROR;
icu::ListFormatter* formatter = icu::ListFormatter::createInstance(
......@@ -198,7 +187,22 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize(
Handle<Managed<icu::ListFormatter>> managed_formatter =
Managed<icu::ListFormatter>::FromRawPtr(isolate, 0, formatter);
// Now all properties are ready, so we can allocate the result object.
Handle<JSListFormat> list_format = Handle<JSListFormat>::cast(
isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
DisallowHeapAllocation no_gc;
list_format->set_flags(0);
list_format->set_icu_formatter(*managed_formatter);
// 11. Set listFormat.[[Locale]] to r.[[Locale]].
list_format->set_locale(*locale_str);
// 13. Set listFormat.[[Type]] to t.
list_format->set_type(type_enum);
// 15. Set listFormat.[[Style]] to s.
list_format->set_style(style_enum);
return list_format;
}
......
......@@ -30,11 +30,11 @@ namespace internal {
class JSListFormat : public JSObject {
public:
// Initializes relative time format object with properties derived from input
// Creates relative time format object with properties derived from input
// locales and options.
static MaybeHandle<JSListFormat> Initialize(
Isolate* isolate, Handle<JSListFormat> list_format_holder,
Handle<Object> locales, Handle<Object> options);
static MaybeHandle<JSListFormat> New(Isolate* isolate, Handle<Map> map,
Handle<Object> locales,
Handle<Object> options);
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSListFormat> format_holder);
......
......@@ -2003,13 +2003,9 @@ MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor,
ASSIGN_RETURN_ON_EXCEPTION(
isolate, initial_map,
JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject);
Handle<JSObject> result = isolate->factory()->NewJSObjectFromMap(
initial_map, AllocationType::kYoung, site);
if (initial_map->is_dictionary_map()) {
Handle<NameDictionary> dictionary =
NameDictionary::New(isolate, NameDictionary::kInitialCapacity);
result->SetProperties(*dictionary);
}
Handle<JSObject> result = isolate->factory()->NewFastOrSlowJSObjectFromMap(
initial_map, NameDictionary::kInitialCapacity, AllocationType::kYoung,
site);
isolate->counters()->constructed_objects()->Increment();
isolate->counters()->constructed_objects_runtime()->Increment();
return result;
......@@ -2027,13 +2023,7 @@ MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate,
Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype));
// Actually allocate the object.
Handle<JSObject> object;
if (map->is_dictionary_map()) {
object = isolate->factory()->NewSlowJSObjectFromMap(map);
} else {
object = isolate->factory()->NewJSObjectFromMap(map);
}
return object;
return isolate->factory()->NewFastOrSlowJSObjectFromMap(map);
}
void JSObject::EnsureWritableFastElements(Handle<JSObject> object) {
......
......@@ -61,10 +61,9 @@ Handle<String> JSPluralRules::TypeAsString() const {
}
// static
MaybeHandle<JSPluralRules> JSPluralRules::Initialize(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options_obj) {
plural_rules->set_flags(0);
MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map,
Handle<Object> locales,
Handle<Object> options_obj) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> maybe_requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales);
......@@ -104,9 +103,6 @@ MaybeHandle<JSPluralRules> JSPluralRules::Initialize(
MAYBE_RETURN(maybe_type, MaybeHandle<JSPluralRules>());
Type type = maybe_type.FromJust();
// 8. Set pluralRules.[[Type]] to t.
plural_rules->set_type(type);
// Note: The spec says we should do ResolveLocale after performing
// SetNumberFormatDigitOptions but we need the locale to create all
// the ICU data structures.
......@@ -119,11 +115,8 @@ MaybeHandle<JSPluralRules> JSPluralRules::Initialize(
Intl::ResolvedLocale r =
Intl::ResolveLocale(isolate, JSPluralRules::GetAvailableLocales(),
requested_locales, matcher, {});
// 12. Set pluralRules.[[Locale]] to the value of r.[[locale]].
Handle<String> locale_str =
isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str());
plural_rules->set_locale(*locale_str);
icu::number::LocalizedNumberFormatter icu_number_formatter =
icu::number::NumberFormatter::withLocale(r.icu_locale)
......@@ -159,13 +152,26 @@ MaybeHandle<JSPluralRules> JSPluralRules::Initialize(
Handle<Managed<icu::PluralRules>> managed_plural_rules =
Managed<icu::PluralRules>::FromUniquePtr(isolate, 0,
std::move(icu_plural_rules));
plural_rules->set_icu_plural_rules(*managed_plural_rules);
Handle<Managed<icu::number::LocalizedNumberFormatter>>
managed_number_formatter =
Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr(
isolate, 0,
new icu::number::LocalizedNumberFormatter(icu_number_formatter));
// Now all properties are ready, so we can allocate the result object.
Handle<JSPluralRules> plural_rules = Handle<JSPluralRules>::cast(
isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
DisallowHeapAllocation no_gc;
plural_rules->set_flags(0);
// 8. Set pluralRules.[[Type]] to t.
plural_rules->set_type(type);
// 12. Set pluralRules.[[Locale]] to the value of r.[[locale]].
plural_rules->set_locale(*locale_str);
plural_rules->set_icu_plural_rules(*managed_plural_rules);
plural_rules->set_icu_number_formatter(*managed_number_formatter);
// 13. Return pluralRules.
......
......@@ -33,9 +33,9 @@ namespace internal {
class JSPluralRules : public JSObject {
public:
V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> Initialize(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options);
V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> New(
Isolate* isolate, Handle<Map> map, Handle<Object> locales,
Handle<Object> options);
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSPluralRules> plural_rules);
......
......@@ -54,11 +54,9 @@ JSRelativeTimeFormat::Numeric JSRelativeTimeFormat::getNumeric(
UNREACHABLE();
}
MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
Isolate* isolate, Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> locales, Handle<Object> input_options) {
relative_time_format_holder->set_flags(0);
MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::New(
Isolate* isolate, Handle<Map> map, Handle<Object> locales,
Handle<Object> input_options) {
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> maybe_requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales);
......@@ -125,7 +123,6 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(
maybe_locale_str.FromJust().c_str());
relative_time_format_holder->set_locale(*locale_str);
// 15. Let s be ? GetOption(options, "style", "string",
// «"long", "short", "narrow"», "long").
......@@ -136,9 +133,6 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
MAYBE_RETURN(maybe_style, MaybeHandle<JSRelativeTimeFormat>());
Style style_enum = maybe_style.FromJust();
// 16. Set relativeTimeFormat.[[Style]] to s.
relative_time_format_holder->set_style(style_enum);
// 17. Let numeric be ? GetOption(options, "numeric", "string",
// «"always", "auto"», "always").
Maybe<Numeric> maybe_numeric = Intl::GetStringOption<Numeric>(
......@@ -147,9 +141,6 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
MAYBE_RETURN(maybe_numeric, MaybeHandle<JSRelativeTimeFormat>());
Numeric numeric_enum = maybe_numeric.FromJust();
// 18. Set relativeTimeFormat.[[Numeric]] to numeric.
relative_time_format_holder->set_numeric(numeric_enum);
// 19. Let relativeTimeFormat.[[NumberFormat]] be
// ? Construct(%NumberFormat%, « nfLocale, nfOptions »).
icu::NumberFormat* number_format =
......@@ -179,6 +170,21 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize(
Managed<icu::RelativeDateTimeFormatter>::FromRawPtr(isolate, 0,
icu_formatter);
// Now all properties are ready, so we can allocate the result object.
Handle<JSRelativeTimeFormat> relative_time_format_holder =
Handle<JSRelativeTimeFormat>::cast(
isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
DisallowHeapAllocation no_gc;
relative_time_format_holder->set_flags(0);
relative_time_format_holder->set_locale(*locale_str);
// 16. Set relativeTimeFormat.[[Style]] to s.
relative_time_format_holder->set_style(style_enum);
// 18. Set relativeTimeFormat.[[Numeric]] to numeric.
relative_time_format_holder->set_numeric(numeric_enum);
// 21. Set relativeTimeFormat.[[InitializedRelativeTimeFormat]] to true.
relative_time_format_holder->set_icu_formatter(*managed_formatter);
......
......@@ -30,12 +30,11 @@ namespace internal {
class JSRelativeTimeFormat : public JSObject {
public:
// Initializes relative time format object with properties derived from input
// Creates relative time format object with properties derived from input
// locales and options.
V8_WARN_UNUSED_RESULT static MaybeHandle<JSRelativeTimeFormat> Initialize(
Isolate* isolate,
Handle<JSRelativeTimeFormat> relative_time_format_holder,
Handle<Object> locales, Handle<Object> options);
V8_WARN_UNUSED_RESULT static MaybeHandle<JSRelativeTimeFormat> New(
Isolate* isolate, Handle<Map> map, Handle<Object> locales,
Handle<Object> options);
V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSRelativeTimeFormat> format_holder);
......
......@@ -30,11 +30,9 @@ JSSegmenter::Granularity JSSegmenter::GetGranularity(const char* str) {
UNREACHABLE();
}
MaybeHandle<JSSegmenter> JSSegmenter::Initialize(
Isolate* isolate, Handle<JSSegmenter> segmenter_holder,
Handle<Object> locales, Handle<Object> input_options) {
segmenter_holder->set_flags(0);
MaybeHandle<JSSegmenter> JSSegmenter::New(Isolate* isolate, Handle<Map> map,
Handle<Object> locales,
Handle<Object> input_options) {
// 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
Maybe<std::vector<std::string>> maybe_requested_locales =
Intl::CanonicalizeLocaleList(isolate, locales);
......@@ -69,11 +67,8 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize(
Intl::ResolvedLocale r =
Intl::ResolveLocale(isolate, JSSegmenter::GetAvailableLocales(),
requested_locales, matcher, {});
// 10. Set segmenter.[[Locale]] to the value of r.[[Locale]].
Handle<String> locale_str =
isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str());
segmenter_holder->set_locale(*locale_str);
// 13. Let granularity be ? GetOption(options, "granularity", "string", «
// "grapheme", "word", "sentence" », "grapheme").
......@@ -85,9 +80,6 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize(
MAYBE_RETURN(maybe_granularity, MaybeHandle<JSSegmenter>());
Granularity granularity_enum = maybe_granularity.FromJust();
// 14. Set segmenter.[[SegmenterGranularity]] to granularity.
segmenter_holder->set_granularity(granularity_enum);
icu::Locale icu_locale = r.icu_locale;
DCHECK(!icu_locale.isBogus());
......@@ -118,6 +110,18 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize(
Managed<icu::BreakIterator>::FromUniquePtr(isolate, 0,
std::move(icu_break_iterator));
// Now all properties are ready, so we can allocate the result object.
Handle<JSSegmenter> segmenter_holder = Handle<JSSegmenter>::cast(
isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
DisallowHeapAllocation no_gc;
segmenter_holder->set_flags(0);
// 10. Set segmenter.[[Locale]] to the value of r.[[Locale]].
segmenter_holder->set_locale(*locale_str);
// 14. Set segmenter.[[SegmenterGranularity]] to granularity.
segmenter_holder->set_granularity(granularity_enum);
segmenter_holder->set_icu_break_iterator(*managed_break_iterator);
return segmenter_holder;
}
......
......@@ -30,11 +30,11 @@ namespace internal {
class JSSegmenter : public JSObject {
public:
// Initializes segmenter object with properties derived from input
// locales and options.
V8_WARN_UNUSED_RESULT static MaybeHandle<JSSegmenter> Initialize(
Isolate* isolate, Handle<JSSegmenter> segmenter_holder,
Handle<Object> locales, Handle<Object> options);
// Creates segmenter object with properties derived from input locales and
// options.
V8_WARN_UNUSED_RESULT static MaybeHandle<JSSegmenter> New(
Isolate* isolate, Handle<Map> map, Handle<Object> locales,
Handle<Object> options);
V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions(
Isolate* isolate, Handle<JSSegmenter> segmenter_holder);
......
......@@ -351,10 +351,8 @@ struct ObjectLiteralHelper {
native_context, number_of_properties);
Handle<JSObject> boilerplate =
map->is_dictionary_map()
? isolate->factory()->NewSlowJSObjectFromMap(
map, number_of_properties, allocation)
: isolate->factory()->NewJSObjectFromMap(map, allocation);
isolate->factory()->NewFastOrSlowJSObjectFromMap(
map, number_of_properties, allocation);
// Normalize the elements of the boilerplate to save space if needed.
if (!use_fast_elements) JSObject::NormalizeElements(boilerplate);
......
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