[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: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#62123}
This commit is contained in:
parent
2f2657a6af
commit
3834c6377c
@ -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);
|
||||
|
@ -8,30 +8,77 @@ namespace typed_array_createtypedarray {
|
||||
extern builtin IterableToListMayPreserveHoles(Context, Object, Callable):
|
||||
JSArray;
|
||||
|
||||
extern macro ConstructorBuiltinsAssembler::EmitFastNewObject(
|
||||
implicit context: Context)(JSFunction, JSReceiver): JSTypedArray;
|
||||
extern macro TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
|
||||
implicit context: Context)(JSTypedArray, uintptr): JSArrayBuffer;
|
||||
implicit context: Context)(uintptr): JSArrayBuffer;
|
||||
extern macro CodeStubAssembler::AllocateByteArray(uintptr): ByteArray;
|
||||
extern macro TypedArrayBuiltinsAssembler::GetDefaultConstructor(
|
||||
implicit context: Context)(JSTypedArray): JSFunction;
|
||||
extern macro TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(JSArrayBuffer):
|
||||
bool;
|
||||
extern macro TypedArrayBuiltinsAssembler::SetupTypedArray(
|
||||
JSTypedArray, uintptr, uintptr, uintptr): void;
|
||||
extern macro TypedArrayBuiltinsAssembler::SetupTypedArrayEmbedderFields(
|
||||
JSTypedArray): void;
|
||||
|
||||
extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)(
|
||||
Map, String): never;
|
||||
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
|
||||
void;
|
||||
|
||||
transitioning macro AllocateTypedArray(implicit context: Context)(
|
||||
isOnHeap: constexpr bool, map: Map, buffer: JSArrayBuffer,
|
||||
byteOffset: uintptr, byteLength: uintptr, length: uintptr): JSTypedArray {
|
||||
let elements: ByteArray;
|
||||
let externalPointer: RawPtr;
|
||||
let basePointer: ByteArray | Smi;
|
||||
if constexpr (isOnHeap) {
|
||||
elements = AllocateByteArray(byteLength);
|
||||
basePointer = elements;
|
||||
externalPointer = PointerConstant(kExternalPointerForOnHeapArray);
|
||||
} else {
|
||||
basePointer = Convert<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: RawPtr = buffer.backing_store;
|
||||
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));
|
||||
|
||||
elements = kEmptyByteArray;
|
||||
}
|
||||
|
||||
// We can't just build the new object with "new JSTypedArray" here because
|
||||
// Torque doesn't know its full size including embedder fields, so use CSA
|
||||
// for the allocation step.
|
||||
const typedArray =
|
||||
UnsafeCast<JSTypedArray>(AllocateFastOrSlowJSObjectFromMap(map));
|
||||
typedArray.elements = elements;
|
||||
typedArray.buffer = buffer;
|
||||
typedArray.byte_offset = byteOffset;
|
||||
typedArray.byte_length = byteLength;
|
||||
typedArray.length = length;
|
||||
typedArray.external_pointer = externalPointer;
|
||||
typedArray.base_pointer = basePointer;
|
||||
SetupTypedArrayEmbedderFields(typedArray);
|
||||
return typedArray;
|
||||
}
|
||||
|
||||
transitioning macro TypedArrayInitialize(implicit context: Context)(
|
||||
initialize: constexpr bool, typedArray: JSTypedArray, length: PositiveSmi,
|
||||
initialize: constexpr bool, map: Map, length: PositiveSmi,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo,
|
||||
bufferConstructor: JSReceiver): uintptr {
|
||||
bufferConstructor: JSReceiver): JSTypedArray {
|
||||
const byteLength = elementsInfo.CalculateByteLength(length)
|
||||
otherwise ThrowRangeError(kInvalidArrayBufferLength);
|
||||
const byteLengthNum = Convert<Number>(byteLength);
|
||||
const defaultConstructor = GetArrayBufferFunction();
|
||||
const byteOffset: uintptr = 0;
|
||||
|
||||
try {
|
||||
if (bufferConstructor != defaultConstructor) {
|
||||
@ -41,12 +88,19 @@ namespace typed_array_createtypedarray {
|
||||
|
||||
if (byteLength > V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP) goto AllocateOffHeap;
|
||||
|
||||
AllocateEmptyOnHeapBuffer(typedArray, byteLength);
|
||||
const buffer = AllocateEmptyOnHeapBuffer(byteLength);
|
||||
|
||||
const isOnHeap: constexpr bool = true;
|
||||
const typedArray = AllocateTypedArray(
|
||||
isOnHeap, map, buffer, byteOffset, byteLength,
|
||||
Convert<uintptr>(length));
|
||||
|
||||
if constexpr (initialize) {
|
||||
const backingStore = typedArray.data_ptr;
|
||||
typed_array::CallCMemset(backingStore, 0, byteLength);
|
||||
}
|
||||
|
||||
return typedArray;
|
||||
}
|
||||
label AllocateOffHeap {
|
||||
if constexpr (initialize) {
|
||||
@ -58,22 +112,18 @@ namespace typed_array_createtypedarray {
|
||||
}
|
||||
label AttachOffHeapBuffer(bufferObj: Object) {
|
||||
const buffer = Cast<JSArrayBuffer>(bufferObj) otherwise unreachable;
|
||||
const byteOffset: uintptr = 0;
|
||||
typedArray.AttachOffHeapBuffer(buffer, byteOffset);
|
||||
const isOnHeap: constexpr bool = false;
|
||||
return AllocateTypedArray(
|
||||
isOnHeap, map, buffer, byteOffset, byteLength,
|
||||
Convert<uintptr>(length));
|
||||
}
|
||||
|
||||
const byteOffset: uintptr = 0;
|
||||
SetupTypedArray(
|
||||
typedArray, Convert<uintptr>(length), byteOffset, byteLength);
|
||||
|
||||
return byteLength;
|
||||
}
|
||||
|
||||
// 22.2.4.2 TypedArray ( length )
|
||||
// ES #sec-typedarray-length
|
||||
transitioning macro ConstructByLength(implicit context: Context)(
|
||||
typedArray: JSTypedArray, length: Object,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo): void {
|
||||
map: Map, length: Object,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray {
|
||||
const convertedLength: Number =
|
||||
ToInteger_Inline(context, length, kTruncateMinusZero);
|
||||
// The maximum length of a TypedArray is MaxSmi().
|
||||
@ -84,23 +134,22 @@ namespace typed_array_createtypedarray {
|
||||
otherwise ThrowRangeError(kInvalidTypedArrayLength, length);
|
||||
const defaultConstructor: Constructor = GetArrayBufferFunction();
|
||||
const initialize: constexpr bool = true;
|
||||
TypedArrayInitialize(
|
||||
initialize, typedArray, positiveLength, elementsInfo,
|
||||
defaultConstructor);
|
||||
return TypedArrayInitialize(
|
||||
initialize, map, positiveLength, elementsInfo, defaultConstructor);
|
||||
}
|
||||
|
||||
// 22.2.4.4 TypedArray ( object )
|
||||
// ES #sec-typedarray-object
|
||||
transitioning macro ConstructByArrayLike(implicit context: Context)(
|
||||
typedArray: JSTypedArray, arrayLike: HeapObject, initialLength: Object,
|
||||
map: Map, arrayLike: HeapObject, initialLength: Object,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo,
|
||||
bufferConstructor: JSReceiver): void {
|
||||
bufferConstructor: JSReceiver): JSTypedArray {
|
||||
// The caller has looked up length on arrayLike, which is observable.
|
||||
const length: PositiveSmi = ToSmiLength(initialLength)
|
||||
otherwise ThrowRangeError(kInvalidTypedArrayLength, initialLength);
|
||||
const initialize: constexpr bool = false;
|
||||
const byteLength = TypedArrayInitialize(
|
||||
initialize, typedArray, length, elementsInfo, bufferConstructor);
|
||||
const typedArray = TypedArrayInitialize(
|
||||
initialize, map, length, elementsInfo, bufferConstructor);
|
||||
|
||||
try {
|
||||
const src: JSTypedArray = Cast<JSTypedArray>(arrayLike) otherwise IfSlow;
|
||||
@ -112,6 +161,7 @@ namespace typed_array_createtypedarray {
|
||||
goto IfSlow;
|
||||
|
||||
} else if (length > 0) {
|
||||
const byteLength = typedArray.byte_length;
|
||||
assert(byteLength <= kArrayBufferMaxByteLength);
|
||||
typed_array::CallCMemcpy(typedArray.data_ptr, src.data_ptr, byteLength);
|
||||
}
|
||||
@ -121,6 +171,7 @@ namespace typed_array_createtypedarray {
|
||||
TypedArrayCopyElements(context, typedArray, arrayLike, length);
|
||||
}
|
||||
}
|
||||
return typedArray;
|
||||
}
|
||||
|
||||
// 22.2.4.4 TypedArray ( object )
|
||||
@ -159,8 +210,8 @@ namespace typed_array_createtypedarray {
|
||||
// 22.2.4.5 TypedArray ( buffer, byteOffset, length )
|
||||
// ES #sec-typedarray-buffer-byteoffset-length
|
||||
transitioning macro ConstructByArrayBuffer(implicit context: Context)(
|
||||
typedArray: JSTypedArray, buffer: JSArrayBuffer, byteOffset: Object,
|
||||
length: Object, elementsInfo: typed_array::TypedArrayElementsInfo): void {
|
||||
map: Map, buffer: JSArrayBuffer, byteOffset: Object, length: Object,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo): JSTypedArray {
|
||||
try {
|
||||
let offset: uintptr = 0;
|
||||
if (byteOffset != Undefined) {
|
||||
@ -222,12 +273,13 @@ namespace typed_array_createtypedarray {
|
||||
goto IfInvalidLength;
|
||||
}
|
||||
|
||||
SetupTypedArray(
|
||||
typedArray, Convert<uintptr>(newLength), offset, newByteLength);
|
||||
typedArray.AttachOffHeapBuffer(buffer, offset);
|
||||
const isOnHeap: constexpr bool = false;
|
||||
return AllocateTypedArray(
|
||||
isOnHeap, map, buffer, offset, newByteLength,
|
||||
Convert<uintptr>(newLength));
|
||||
}
|
||||
label IfInvalidAlignment(problemString: String) deferred {
|
||||
ThrowInvalidTypedArrayAlignment(typedArray.map, problemString);
|
||||
ThrowInvalidTypedArrayAlignment(map, problemString);
|
||||
}
|
||||
label IfInvalidByteLength deferred {
|
||||
ThrowRangeError(kInvalidArrayBufferLength);
|
||||
@ -270,22 +322,12 @@ namespace typed_array_createtypedarray {
|
||||
assert(IsConstructor(target));
|
||||
// 4. Let O be ? AllocateTypedArray(constructorName, NewTarget,
|
||||
// "%TypedArrayPrototype%").
|
||||
const array: JSTypedArray = EmitFastNewObject(target, newTarget);
|
||||
// We need to set the byte_offset / byte_length to some sane values
|
||||
// to keep the heap verifier happy.
|
||||
// TODO(bmeurer, v8:4153): Fix this initialization to not use
|
||||
// EmitFastNewObject, which causes the problem, since it puts
|
||||
// Undefined into all slots of the object even though that
|
||||
// doesn't make any sense for these fields.
|
||||
array.byte_offset = 0;
|
||||
array.byte_length = 0;
|
||||
array.length = 0;
|
||||
array.base_pointer = Convert<Smi>(0);
|
||||
const map = GetDerivedMap(target, newTarget);
|
||||
|
||||
// 5. Let elementSize be the Number value of the Element Size value in Table
|
||||
// 56 for constructorName.
|
||||
const elementsInfo: typed_array::TypedArrayElementsInfo =
|
||||
typed_array::GetTypedArrayElementsInfo(array);
|
||||
typed_array::GetTypedArrayElementsInfo(map);
|
||||
|
||||
try {
|
||||
typeswitch (arg1) {
|
||||
@ -293,7 +335,7 @@ namespace typed_array_createtypedarray {
|
||||
goto IfConstructByLength(length);
|
||||
}
|
||||
case (buffer: JSArrayBuffer): {
|
||||
ConstructByArrayBuffer(array, buffer, arg2, arg3, elementsInfo);
|
||||
return ConstructByArrayBuffer(map, buffer, arg2, arg3, elementsInfo);
|
||||
}
|
||||
case (typedArray: JSTypedArray): {
|
||||
ConstructByTypedArray(typedArray) otherwise IfConstructByArrayLike;
|
||||
@ -309,14 +351,13 @@ namespace typed_array_createtypedarray {
|
||||
}
|
||||
}
|
||||
label IfConstructByLength(length: Object) {
|
||||
ConstructByLength(array, length, elementsInfo);
|
||||
return ConstructByLength(map, length, elementsInfo);
|
||||
}
|
||||
label IfConstructByArrayLike(
|
||||
arrayLike: HeapObject, length: Object, bufferConstructor: JSReceiver) {
|
||||
ConstructByArrayLike(
|
||||
array, arrayLike, length, elementsInfo, bufferConstructor);
|
||||
return ConstructByArrayLike(
|
||||
map, arrayLike, length, elementsInfo, bufferConstructor);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
transitioning macro TypedArraySpeciesCreate(implicit context: Context)(
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user