From 6d79ceb2945bc23a33ac5c93285a2cab2ba2e126 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 21 Apr 2015 06:07:32 -0700 Subject: [PATCH] LayoutDescriptor should inherit from JSTypedArray It can't just inherit from a FixedTypedArray-like type, as we soon assume that a FixedTypedArray-like type is always held by an ArrayBufferView-like type BUG=v8:3996 R=ishell@chromium.org,verwaest@chromium.org LOG=n Review URL: https://codereview.chromium.org/1084793004 Cr-Commit-Position: refs/heads/master@{#27964} --- src/factory.cc | 89 ++++++++++++++++++++++++++++- src/factory.h | 6 ++ src/layout-descriptor-inl.h | 20 ++++++- src/layout-descriptor.cc | 23 ++++++-- src/layout-descriptor.h | 5 +- src/objects-inl.h | 4 +- src/objects-printer.cc | 2 +- test/cctest/test-unboxed-doubles.cc | 8 +-- 8 files changed, 137 insertions(+), 20 deletions(-) diff --git a/src/factory.cc b/src/factory.cc index eda7cdda84..1047711b65 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1825,9 +1825,38 @@ size_t GetExternalArrayElementSize(ExternalArrayType type) { case kExternal##Type##Array: \ return size; TYPED_ARRAYS(TYPED_ARRAY_CASE) + default: + UNREACHABLE(); + return 0; + } +#undef TYPED_ARRAY_CASE +} + + +size_t GetFixedTypedArraysElementSize(ElementsKind kind) { + switch (kind) { +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: \ + return size; + TYPED_ARRAYS(TYPED_ARRAY_CASE) + default: + UNREACHABLE(); + return 0; + } +#undef TYPED_ARRAY_CASE +} + + +ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) { + switch (kind) { +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: \ + return kExternal##Type##Array; + TYPED_ARRAYS(TYPED_ARRAY_CASE) + default: + UNREACHABLE(); + return kExternalInt8Array; } - UNREACHABLE(); - return 0; #undef TYPED_ARRAY_CASE } @@ -1849,6 +1878,23 @@ JSFunction* GetTypedArrayFun(ExternalArrayType type, Isolate* isolate) { } +JSFunction* GetTypedArrayFun(ElementsKind elements_kind, Isolate* isolate) { + Context* native_context = isolate->context()->native_context(); + switch (elements_kind) { +#define TYPED_ARRAY_FUN(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: \ + return native_context->type##_array_fun(); + + TYPED_ARRAYS(TYPED_ARRAY_FUN) +#undef TYPED_ARRAY_FUN + + default: + UNREACHABLE(); + return NULL; + } +} + + void SetupArrayBufferView(i::Isolate* isolate, i::Handle obj, i::Handle buffer, @@ -1890,6 +1936,16 @@ Handle Factory::NewJSTypedArray(ExternalArrayType type) { } +Handle Factory::NewJSTypedArray(ElementsKind elements_kind) { + Handle typed_array_fun_handle( + GetTypedArrayFun(elements_kind, isolate())); + + CALL_HEAP_FUNCTION( + isolate(), isolate()->heap()->AllocateJSObject(*typed_array_fun_handle), + JSTypedArray); +} + + Handle Factory::NewJSTypedArray(ExternalArrayType type, Handle buffer, size_t byte_offset, @@ -1918,6 +1974,35 @@ Handle Factory::NewJSTypedArray(ExternalArrayType type, } +Handle Factory::NewJSTypedArray(ElementsKind elements_kind, + size_t number_of_elements) { + Handle obj = NewJSTypedArray(elements_kind); + + size_t element_size = GetFixedTypedArraysElementSize(elements_kind); + ExternalArrayType array_type = GetArrayTypeFromElementsKind(elements_kind); + + CHECK(number_of_elements <= + (std::numeric_limits::max() / element_size)); + CHECK(number_of_elements <= static_cast(Smi::kMaxValue)); + size_t byte_length = number_of_elements * element_size; + + obj->set_byte_offset(Smi::FromInt(0)); + i::Handle byte_length_object = + isolate()->factory()->NewNumberFromSize(byte_length); + obj->set_byte_length(*byte_length_object); + Handle length_object = NewNumberFromSize(number_of_elements); + obj->set_length(*length_object); + + obj->set_buffer(Smi::FromInt(0)); + obj->set_weak_next(isolate()->heap()->undefined_value()); + Handle elements = + isolate()->factory()->NewFixedTypedArray( + static_cast(number_of_elements), array_type); + obj->set_elements(*elements); + return obj; +} + + Handle Factory::NewJSDataView(Handle buffer, size_t byte_offset, size_t byte_length) { diff --git a/src/factory.h b/src/factory.h index 87ec2e6e70..72991d9bf0 100644 --- a/src/factory.h +++ b/src/factory.h @@ -448,11 +448,17 @@ class Factory final { Handle NewJSTypedArray(ExternalArrayType type); + Handle NewJSTypedArray(ElementsKind elements_kind); + // Creates a new JSTypedArray with the specified buffer. Handle NewJSTypedArray(ExternalArrayType type, Handle buffer, size_t byte_offset, size_t length); + // Creates a new on-heap JSTypedArray. + Handle NewJSTypedArray(ElementsKind elements_kind, + size_t number_of_elements); + Handle NewJSDataView(); Handle NewJSDataView(Handle buffer, size_t byte_offset, size_t byte_length); diff --git a/src/layout-descriptor-inl.h b/src/layout-descriptor-inl.h index ba76704d5f..c7b0f71dac 100644 --- a/src/layout-descriptor-inl.h +++ b/src/layout-descriptor-inl.h @@ -22,7 +22,7 @@ Handle LayoutDescriptor::New(Isolate* isolate, int length) { } length = GetSlowModeBackingStoreLength(length); return Handle::cast( - isolate->factory()->NewFixedTypedArray(length, kExternalUint32Array)); + isolate->factory()->NewJSTypedArray(UINT32_ELEMENTS, length)); } @@ -48,7 +48,7 @@ bool LayoutDescriptor::GetIndexes(int field_index, int* layout_word_index, } *layout_word_index = field_index / kNumberOfBits; - CHECK((!IsSmi() && (*layout_word_index < length())) || + CHECK((!IsSmi() && (*layout_word_index < Smi::cast(length())->value())) || (IsSmi() && (*layout_word_index < 1))); *layout_bit_index = field_index % kNumberOfBits; @@ -123,7 +123,21 @@ bool LayoutDescriptor::IsSlowLayout() { return !IsSmi(); } int LayoutDescriptor::capacity() { - return IsSlowLayout() ? (length() * kNumberOfBits) : kSmiValueSize; + return IsSlowLayout() ? (Smi::cast(length())->value() * kNumberOfBits) + : kSmiValueSize; +} + + +uint32_t LayoutDescriptor::get_scalar(int index) { + DCHECK(IsSlowLayout()); + return FixedTypedArray::cast(elements()) + ->get_scalar(index); +} + + +void LayoutDescriptor::set(int index, uint32_t value) { + DCHECK(IsSlowLayout()); + FixedTypedArray::cast(elements())->set(index, value); } diff --git a/src/layout-descriptor.cc b/src/layout-descriptor.cc index 66a1f0fb07..312429f0c6 100644 --- a/src/layout-descriptor.cc +++ b/src/layout-descriptor.cc @@ -106,8 +106,12 @@ Handle LayoutDescriptor::EnsureCapacity( DCHECK(new_layout_descriptor->IsSlowLayout()); if (layout_descriptor->IsSlowLayout()) { - memcpy(new_layout_descriptor->DataPtr(), layout_descriptor->DataPtr(), - layout_descriptor->DataSize()); + DisallowHeapAllocation no_gc; + Handle elements( + FixedTypedArrayBase::cast(layout_descriptor->elements())); + Handle new_elements( + FixedTypedArrayBase::cast(new_layout_descriptor->elements())); + memcpy(new_elements->DataPtr(), elements->DataPtr(), elements->DataSize()); return new_layout_descriptor; } else { // Fast layout. @@ -150,7 +154,7 @@ bool LayoutDescriptor::IsTagged(int field_index, int max_sequence_length, // This is a contiguous sequence till the end of current word, proceed // counting in the subsequent words. if (IsSlowLayout()) { - int len = length(); + int len = Smi::cast(length())->value(); ++layout_word_index; for (; layout_word_index < len; layout_word_index++) { value = get_scalar(layout_word_index); @@ -241,13 +245,20 @@ LayoutDescriptor* LayoutDescriptor::Trim(Heap* heap, Map* map, // Trim, clean and reinitialize this slow-mode layout descriptor. int array_length = GetSlowModeBackingStoreLength(layout_descriptor_length); - int current_length = length(); + int current_length = Smi::cast(length())->value(); if (current_length != array_length) { DCHECK_LT(array_length, current_length); int delta = current_length - array_length; - heap->RightTrimFixedArray(this, delta); + heap->RightTrimFixedArray(elements(), delta); + set_byte_length(Smi::FromInt(array_length * 4)); + set_length(Smi::FromInt(array_length)); + } + { + DisallowHeapAllocation no_gc; + Handle fixed_array( + FixedTypedArrayBase::cast(elements())); + memset(fixed_array->DataPtr(), 0, fixed_array->DataSize()); } - memset(DataPtr(), 0, DataSize()); LayoutDescriptor* layout_descriptor = Initialize(this, map, descriptors, num_descriptors); DCHECK_EQ(this, layout_descriptor); diff --git a/src/layout-descriptor.h b/src/layout-descriptor.h index 0a14f53198..b68decfa41 100644 --- a/src/layout-descriptor.h +++ b/src/layout-descriptor.h @@ -22,7 +22,7 @@ namespace internal { // of the descriptor then the field is also considered tagged. // Once a layout descriptor is created it is allowed only to append properties // to it. -class LayoutDescriptor : public FixedTypedArray { +class LayoutDescriptor : public JSTypedArray { public: V8_INLINE bool IsTagged(int field_index); @@ -89,6 +89,9 @@ class LayoutDescriptor : public FixedTypedArray { // Capacity of layout descriptors in bits. V8_INLINE int capacity(); + V8_INLINE uint32_t get_scalar(int index); + V8_INLINE void set(int index, uint32_t value); + static Handle NewForTesting(Isolate* isolate, int length); LayoutDescriptor* SetTaggedForTesting(int field_index, bool tagged); diff --git a/src/objects-inl.h b/src/objects-inl.h index 5f3d0747e6..8ff7866f0a 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -716,9 +716,7 @@ bool Object::IsDescriptorArray() const { bool Object::IsArrayList() const { return IsFixedArray(); } -bool Object::IsLayoutDescriptor() const { - return IsSmi() || IsFixedTypedArrayBase(); -} +bool Object::IsLayoutDescriptor() const { return IsSmi() || IsJSTypedArray(); } bool Object::IsTransitionArray() const { diff --git a/src/objects-printer.cc b/src/objects-printer.cc index cb3f27a79b..6e30303370 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -1065,7 +1065,7 @@ void LayoutDescriptor::Print(std::ostream& os) { // NOLINT PrintBitMask(os, static_cast(Smi::cast(this)->value())); } else { os << "slow"; - int len = length(); + int len = Smi::cast(length())->value(); for (int i = 0; i < len; i++) { if (i > 0) os << " |"; PrintBitMask(os, get_scalar(i)); diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc index 75e7d5ae83..a5c225e360 100644 --- a/test/cctest/test-unboxed-doubles.cc +++ b/test/cctest/test-unboxed-doubles.cc @@ -581,7 +581,7 @@ TEST(LayoutDescriptorCreateNewSlow) { LayoutDescriptor* layout_desc = *layout_descriptor; CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc)); CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc)); - CHECK(layout_descriptor->IsFixedTypedArrayBase()); + CHECK(layout_descriptor->IsJSTypedArray()); // Now make it look like a forwarding pointer to layout_descriptor_copy. MapWord map_word = layout_desc->map_word(); CHECK(!map_word.IsForwardingAddress()); @@ -935,7 +935,7 @@ TEST(DescriptorArrayTrimming) { CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true)); CHECK(map->layout_descriptor()->IsSlowLayout()); CHECK(map->owns_descriptors()); - CHECK_EQ(2, map->layout_descriptor()->length()); + CHECK_EQ(2, Smi::cast(map->layout_descriptor()->length())->value()); { // Add transitions to double fields. @@ -954,7 +954,7 @@ TEST(DescriptorArrayTrimming) { CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor()); } CHECK(map->layout_descriptor()->IsSlowLayout()); - CHECK_EQ(4, map->layout_descriptor()->length()); + CHECK_EQ(4, Smi::cast(map->layout_descriptor()->length())->value()); // The unused tail of the layout descriptor is now "durty" because of sharing. CHECK(map->layout_descriptor()->IsConsistentWithMap(*map)); @@ -974,7 +974,7 @@ TEST(DescriptorArrayTrimming) { CHECK_EQ(map->NumberOfOwnDescriptors(), map->instance_descriptors()->number_of_descriptors()); CHECK(map->layout_descriptor()->IsSlowLayout()); - CHECK_EQ(2, map->layout_descriptor()->length()); + CHECK_EQ(2, Smi::cast(map->layout_descriptor()->length())->value()); { // Add transitions to tagged fields.