Commit 6ebe4979 authored by Samuel Groß's avatar Samuel Groß Committed by V8 LUCI CQ

Introduce Fixed{U}Int{8,16,32,64}Array types

This CL introduces new FixedArray subclasses that behave like
fixed-sized arrays of integers. Under the hood, these are just
ByteArrays with integer element accessors.

These new classes will be used in follow-up CLs which moves various
integer arrays from the native heap onto the V8 heap.

Bug: chromium:1335046
Change-Id: Ie7497b4464c1a037e4eaf49e8bf7ac4da62512de
Cq-Include-Trybots: luci.v8.try:v8_linux64_heap_sandbox_dbg_ng,v8_linux_arm64_sim_heap_sandbox_dbg_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3838775Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarJakob Linke <jgruber@chromium.org>
Commit-Queue: Samuel Groß <saelo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82678}
parent a9990e08
......@@ -85,13 +85,13 @@ void BasicBlockProfilerData::CopyFromJSHeap(
function_name_ = js_heap_data.name().ToCString().get();
schedule_ = js_heap_data.schedule().ToCString().get();
code_ = js_heap_data.code().ToCString().get();
ByteArray counts(js_heap_data.counts());
FixedUInt32Array counts = FixedUInt32Array::cast(js_heap_data.counts());
for (int i = 0; i < counts.length() / kBlockCountSlotSize; ++i) {
counts_.push_back(counts.get_uint32(i));
counts_.push_back(counts.get(i));
}
ByteArray block_ids(js_heap_data.block_ids());
FixedInt32Array block_ids(js_heap_data.block_ids());
for (int i = 0; i < block_ids.length() / kBlockIdSlotSize; ++i) {
block_ids_.push_back(block_ids.get_int(i));
block_ids_.push_back(block_ids.get(i));
}
PodArray<std::pair<int32_t, int32_t>> branches = js_heap_data.branches();
for (int i = 0; i < branches.length(); ++i) {
......@@ -107,10 +107,10 @@ Handle<OnHeapBasicBlockProfilerData> BasicBlockProfilerData::CopyToJSHeap(
CHECK(id_array_size_in_bytes >= 0 &&
static_cast<size_t>(id_array_size_in_bytes) / kBlockIdSlotSize ==
n_blocks()); // Overflow
Handle<ByteArray> block_ids = isolate->factory()->NewByteArray(
id_array_size_in_bytes, AllocationType::kOld);
Handle<FixedInt32Array> block_ids = FixedInt32Array::New(
isolate, id_array_size_in_bytes, AllocationType::kOld);
for (int i = 0; i < static_cast<int>(n_blocks()); ++i) {
block_ids->set_int(i, block_ids_[i]);
block_ids->set(i, block_ids_[i]);
}
int counts_array_size_in_bytes =
......@@ -118,10 +118,10 @@ Handle<OnHeapBasicBlockProfilerData> BasicBlockProfilerData::CopyToJSHeap(
CHECK(counts_array_size_in_bytes >= 0 &&
static_cast<size_t>(counts_array_size_in_bytes) / kBlockCountSlotSize ==
n_blocks()); // Overflow
Handle<ByteArray> counts = isolate->factory()->NewByteArray(
counts_array_size_in_bytes, AllocationType::kOld);
Handle<FixedUInt32Array> counts = FixedUInt32Array::New(
isolate, counts_array_size_in_bytes, AllocationType::kOld);
for (int i = 0; i < static_cast<int>(n_blocks()); ++i) {
counts->set_uint32(i, counts_[i]);
counts->set(i, counts_[i]);
}
Handle<PodArray<std::pair<int32_t, int32_t>>> branches =
......@@ -147,10 +147,10 @@ void BasicBlockProfiler::ResetCounts(Isolate* isolate) {
Handle<ArrayList> list(isolate->heap()->basic_block_profiling_data(),
isolate);
for (int i = 0; i < list->Length(); ++i) {
Handle<ByteArray> counts(
Handle<FixedUInt32Array> counts(
OnHeapBasicBlockProfilerData::cast(list->Get(i)).counts(), isolate);
for (int j = 0; j < counts->length() / kBlockCountSlotSize; ++j) {
counts->set_uint32(j, 0);
counts->set(j, 0);
}
}
}
......
......@@ -8,6 +8,7 @@
#include "src/base/export-template.h"
#include "src/base/strings.h"
#include "src/common/globals.h"
#include "src/objects/fixed-array.h"
#include "src/objects/function-kind.h"
#include "src/objects/instance-type.h"
#include "src/roots/roots.h"
......@@ -28,8 +29,6 @@ class RegExpBoilerplateDescription;
class TemplateObjectDescription;
class SourceTextModuleInfo;
class PreparseData;
template <class T>
class PodArray;
class UncompiledDataWithoutPreparseData;
class UncompiledDataWithPreparseData;
class BytecodeArray;
......
......@@ -597,104 +597,106 @@ void ArrayList::Clear(int index, Object undefined) {
int ByteArray::Size() { return RoundUp(length() + kHeaderSize, kTaggedSize); }
byte ByteArray::get(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, length());
return ReadField<byte>(kHeaderSize + index * kCharSize);
byte ByteArray::get(int offset) const {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, length());
return ReadField<byte>(kHeaderSize + offset);
}
void ByteArray::set(int index, byte value) {
DCHECK_GE(index, 0);
DCHECK_LT(index, length());
WriteField<byte>(kHeaderSize + index * kCharSize, value);
void ByteArray::set(int offset, byte value) {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, length());
WriteField<byte>(kHeaderSize + offset, value);
}
void ByteArray::copy_in(int index, const byte* buffer, int slice_length) {
DCHECK_GE(index, 0);
int ByteArray::get_int(int offset) const {
DCHECK_GE(offset, 0);
DCHECK_LE(offset + sizeof(int), length());
return ReadField<int>(kHeaderSize + offset);
}
void ByteArray::set_int(int offset, int value) {
DCHECK_GE(offset, 0);
DCHECK_LE(offset + sizeof(int), length());
WriteField<int>(kHeaderSize + offset, value);
}
void ByteArray::copy_in(int offset, const byte* buffer, int slice_length) {
DCHECK_GE(offset, 0);
DCHECK_GE(slice_length, 0);
DCHECK_LE(slice_length, kMaxInt - index);
DCHECK_LE(index + slice_length, length());
Address dst_addr = field_address(kHeaderSize + index * kCharSize);
DCHECK_LE(slice_length, kMaxInt - offset);
DCHECK_LE(offset + slice_length, length());
Address dst_addr = field_address(kHeaderSize + offset);
memcpy(reinterpret_cast<void*>(dst_addr), buffer, slice_length);
}
void ByteArray::copy_out(int index, byte* buffer, int slice_length) {
DCHECK_GE(index, 0);
void ByteArray::copy_out(int offset, byte* buffer, int slice_length) {
DCHECK_GE(offset, 0);
DCHECK_GE(slice_length, 0);
DCHECK_LE(slice_length, kMaxInt - index);
DCHECK_LE(index + slice_length, length());
Address src_addr = field_address(kHeaderSize + index * kCharSize);
DCHECK_LE(slice_length, kMaxInt - offset);
DCHECK_LE(offset + slice_length, length());
Address src_addr = field_address(kHeaderSize + offset);
memcpy(buffer, reinterpret_cast<void*>(src_addr), slice_length);
}
int ByteArray::get_int(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kIntSize);
return ReadField<int>(kHeaderSize + index * kIntSize);
}
void ByteArray::set_int(int index, int value) {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kIntSize);
WriteField<int>(kHeaderSize + index * kIntSize, value);
void ByteArray::clear_padding() {
int data_size = length() + kHeaderSize;
memset(reinterpret_cast<void*>(address() + data_size), 0, Size() - data_size);
}
uint32_t ByteArray::get_uint32(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kUInt32Size);
return ReadField<uint32_t>(kHeaderSize + index * kUInt32Size);
ByteArray ByteArray::FromDataStartAddress(Address address) {
DCHECK_TAG_ALIGNED(address);
return ByteArray::cast(Object(address - kHeaderSize + kHeapObjectTag));
}
void ByteArray::set_uint32(int index, uint32_t value) {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kUInt32Size);
WriteField<uint32_t>(kHeaderSize + index * kUInt32Size, value);
}
int ByteArray::DataSize() const { return RoundUp(length(), kTaggedSize); }
uint32_t ByteArray::get_uint32_relaxed(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kUInt32Size);
return RELAXED_READ_UINT32_FIELD(*this, kHeaderSize + index * kUInt32Size);
byte* ByteArray::GetDataStartAddress() {
return reinterpret_cast<byte*>(address() + kHeaderSize);
}
void ByteArray::set_uint32_relaxed(int index, uint32_t value) {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kUInt32Size);
RELAXED_WRITE_UINT32_FIELD(*this, kHeaderSize + index * kUInt32Size, value);
byte* ByteArray::GetDataEndAddress() {
return GetDataStartAddress() + length();
}
uint16_t ByteArray::get_uint16(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kUInt16Size);
return ReadField<uint16_t>(kHeaderSize + index * kUInt16Size);
template <typename T>
FixedIntegerArray<T>::FixedIntegerArray(Address ptr) : ByteArray(ptr) {
DCHECK_EQ(ByteArray::length() % sizeof(T), 0);
}
void ByteArray::set_uint16(int index, uint16_t value) {
DCHECK_GE(index, 0);
DCHECK_LT(index, length() / kUInt16Size);
WriteField<uint16_t>(kHeaderSize + index * kUInt16Size, value);
template <typename T>
FixedIntegerArray<T> FixedIntegerArray<T>::cast(Object object) {
return FixedIntegerArray<T>(object.ptr());
}
void ByteArray::clear_padding() {
int data_size = length() + kHeaderSize;
memset(reinterpret_cast<void*>(address() + data_size), 0, Size() - data_size);
// static
template <typename T>
Handle<FixedIntegerArray<T>> FixedIntegerArray<T>::New(
Isolate* isolate, int length, AllocationType allocation) {
return Handle<FixedIntegerArray<T>>::cast(
isolate->factory()->NewByteArray(length * sizeof(T), allocation));
}
ByteArray ByteArray::FromDataStartAddress(Address address) {
DCHECK_TAG_ALIGNED(address);
return ByteArray::cast(Object(address - kHeaderSize + kHeapObjectTag));
template <typename T>
T FixedIntegerArray<T>::get(int index) const {
static_assert(std::is_integral<T>::value);
DCHECK_GE(index, 0);
DCHECK_LT(index, length());
return ReadField<T>(kHeaderSize + index * sizeof(T));
}
int ByteArray::DataSize() const { return RoundUp(length(), kTaggedSize); }
int ByteArray::ByteArraySize() { return SizeFor(length()); }
byte* ByteArray::GetDataStartAddress() {
return reinterpret_cast<byte*>(address() + kHeaderSize);
template <typename T>
void FixedIntegerArray<T>::set(int index, T value) {
static_assert(std::is_integral<T>::value);
DCHECK_GE(index, 0);
DCHECK_LT(index, length());
WriteField<T>(kHeaderSize + index * sizeof(T), value);
}
byte* ByteArray::GetDataEndAddress() {
return GetDataStartAddress() + length();
template <typename T>
int FixedIntegerArray<T>::length() const {
DCHECK_EQ(ByteArray::length() % sizeof(T), 0);
return ByteArray::length() / sizeof(T);
}
template <class T>
......
......@@ -329,7 +329,7 @@ class WeakFixedArray
int AllocatedSize();
static int OffsetOfElementAt(int index) {
static_assert(kObjectsOffset == SizeFor(0));
static_assert(kHeaderSize == SizeFor(0));
return SizeFor(index);
}
......@@ -518,33 +518,23 @@ inline int Search(T* array, Name name, int valid_entries = 0,
int* out_insertion_index = nullptr,
bool concurrent_search = false);
// ByteArray represents fixed sized byte arrays. Used for the relocation info
// that is attached to code objects.
// ByteArray represents fixed sized arrays containing raw bytes that will not
// be scanned by the garbage collector.
class ByteArray : public TorqueGeneratedByteArray<ByteArray, FixedArrayBase> {
public:
inline int Size();
// Setter and getter.
inline byte get(int index) const;
inline void set(int index, byte value);
// Get/set the contents of this array.
inline byte get(int offset) const;
inline void set(int offset, byte value);
inline int get_int(int offset) const;
inline void set_int(int offset, int value);
// Copy in / copy out whole byte slices.
inline void copy_out(int index, byte* buffer, int slice_length);
inline void copy_in(int index, const byte* buffer, int slice_length);
// Treat contents as an int array.
inline int get_int(int index) const;
inline void set_int(int index, int value);
inline uint32_t get_uint32(int index) const;
inline void set_uint32(int index, uint32_t value);
inline uint32_t get_uint32_relaxed(int index) const;
inline void set_uint32_relaxed(int index, uint32_t value);
inline uint16_t get_uint16(int index) const;
inline void set_uint16(int index, uint16_t value);
// Clear uninitialized padding space. This ensures that the snapshot content
// is deterministic.
inline void clear_padding();
......@@ -572,8 +562,10 @@ class ByteArray : public TorqueGeneratedByteArray<ByteArray, FixedArrayBase> {
// Returns a pointer to the ByteArray object for a given data start address.
static inline ByteArray FromDataStartAddress(Address address);
// Code Generation support.
static int OffsetOfElementAt(int index) { return kHeaderSize + index; }
// Dispatched behavior.
inline int ByteArraySize();
DECL_PRINTER(ByteArray)
// Layout description.
......@@ -591,6 +583,41 @@ class ByteArray : public TorqueGeneratedByteArray<ByteArray, FixedArrayBase> {
inline ByteArray(Address ptr, HeapObject::AllowInlineSmiStorage allow_smi);
};
// Convenience class for treating a ByteArray as array of fixed-size integers.
template <typename T>
class FixedIntegerArray : public ByteArray {
static_assert(std::is_integral<T>::value);
public:
static Handle<FixedIntegerArray<T>> New(
Isolate* isolate, int length,
AllocationType allocation = AllocationType::kYoung);
// Get/set the contents of this array.
T get(int index) const;
void set(int index, T value);
// Code Generation support.
static constexpr int OffsetOfElementAt(int index) {
return kHeaderSize + index * sizeof(T);
}
inline int length() const;
DECL_CAST(FixedIntegerArray<T>)
OBJECT_CONSTRUCTORS(FixedIntegerArray<T>, ByteArray);
};
using FixedInt8Array = FixedIntegerArray<int8_t>;
using FixedUInt8Array = FixedIntegerArray<uint8_t>;
using FixedInt16Array = FixedIntegerArray<int16_t>;
using FixedUInt16Array = FixedIntegerArray<uint16_t>;
using FixedInt32Array = FixedIntegerArray<int32_t>;
using FixedUInt32Array = FixedIntegerArray<uint32_t>;
using FixedInt64Array = FixedIntegerArray<int64_t>;
using FixedUInt64Array = FixedIntegerArray<uint64_t>;
// Wrapper class for ByteArray which can store arbitrary C++ classes, as long
// as they can be copied with memcpy.
template <class T>
......
......@@ -289,11 +289,6 @@ namespace InstanceTypeChecker {
INSTANCE_TYPE_CHECKERS(IS_TYPE_FUNCTION_DECL)
#define TYPED_ARRAY_IS_TYPE_FUNCTION_DECL(Type, ...) \
IS_TYPE_FUNCTION_DECL(Fixed##Type##Array)
TYPED_ARRAYS(TYPED_ARRAY_IS_TYPE_FUNCTION_DECL)
#undef TYPED_ARRAY_IS_TYPE_FUNCTION_DECL
IS_TYPE_FUNCTION_DECL(CodeT)
#undef IS_TYPE_FUNCTION_DECL
......
......@@ -151,11 +151,17 @@ extern class UncompiledDataWithPreparseDataAndJob extends
type PodArrayOfIntegerPairs extends ByteArray
constexpr 'PodArray<std::pair<int32_t, int32_t>>';
@useParentTypeChecker
type FixedInt32Array extends ByteArray constexpr 'FixedInt32Array';
@useParentTypeChecker
type FixedUInt32Array extends ByteArray constexpr 'FixedUInt32Array';
@export
class OnHeapBasicBlockProfilerData extends HeapObject {
block_ids: ByteArray; // Stored as 4-byte ints
counts: ByteArray; // Stored as 4-byte unsigned ints
branches: PodArrayOfIntegerPairs; // Stored as pairs of 4-byte ints
block_ids: FixedInt32Array;
counts: FixedUInt32Array;
branches: PodArrayOfIntegerPairs;
name: String;
schedule: String;
code: String;
......
......@@ -129,37 +129,36 @@ int RangeArrayLengthFor(const ZoneList<CharacterRange>* ranges) {
: ranges_length * 2;
}
bool Equals(const ZoneList<CharacterRange>* lhs, const Handle<ByteArray>& rhs) {
DCHECK_EQ(rhs->length() % kUInt16Size, 0); // uc16 elements.
const int rhs_length = rhs->length() / kUInt16Size;
bool Equals(const ZoneList<CharacterRange>* lhs,
const Handle<FixedUInt16Array>& rhs) {
const int rhs_length = rhs->length();
if (rhs_length != RangeArrayLengthFor(lhs)) return false;
for (int i = 0; i < lhs->length(); i++) {
const CharacterRange& r = lhs->at(i);
if (rhs->get_uint16(i * 2 + 0) != r.from()) return false;
if (rhs->get(i * 2 + 0) != r.from()) return false;
if (i * 2 + 1 == rhs_length) break;
if (rhs->get_uint16(i * 2 + 1) != r.to() + 1) return false;
if (rhs->get(i * 2 + 1) != r.to() + 1) return false;
}
return true;
}
Handle<ByteArray> MakeRangeArray(Isolate* isolate,
const ZoneList<CharacterRange>* ranges) {
Handle<FixedUInt16Array> MakeRangeArray(
Isolate* isolate, const ZoneList<CharacterRange>* ranges) {
const int ranges_length = ranges->length();
const int byte_array_length = RangeArrayLengthFor(ranges);
const int size_in_bytes = byte_array_length * kUInt16Size;
Handle<ByteArray> range_array =
isolate->factory()->NewByteArray(size_in_bytes);
const int range_array_length = RangeArrayLengthFor(ranges);
Handle<FixedUInt16Array> range_array =
FixedUInt16Array::New(isolate, range_array_length);
for (int i = 0; i < ranges_length; i++) {
const CharacterRange& r = ranges->at(i);
DCHECK_LE(r.from(), kMaxUInt16);
range_array->set_uint16(i * 2 + 0, r.from());
range_array->set(i * 2 + 0, r.from());
const base::uc32 to = MaskEndOfRangeMarker(r.to());
if (i == ranges_length - 1 && to == kMaxUInt16) {
DCHECK_EQ(byte_array_length, ranges_length * 2 - 1);
DCHECK_EQ(range_array_length, ranges_length * 2 - 1);
break; // Avoid overflow by leaving the last range open-ended.
}
DCHECK_LT(to, kMaxUInt16);
range_array->set_uint16(i * 2 + 1, to + 1); // Exclusive.
range_array->set(i * 2 + 1, to + 1); // Exclusive.
}
return range_array;
}
......@@ -171,11 +170,11 @@ Handle<ByteArray> NativeRegExpMacroAssembler::GetOrAddRangeArray(
const uint32_t hash = Hash(ranges);
if (range_array_cache_.count(hash) != 0) {
Handle<ByteArray> range_array = range_array_cache_[hash];
Handle<FixedUInt16Array> range_array = range_array_cache_[hash];
if (Equals(ranges, range_array)) return range_array;
}
Handle<ByteArray> range_array = MakeRangeArray(isolate(), ranges);
Handle<FixedUInt16Array> range_array = MakeRangeArray(isolate(), ranges);
range_array_cache_[hash] = range_array;
return range_array;
}
......@@ -189,27 +188,24 @@ uint32_t RegExpMacroAssembler::IsCharacterInRangeArray(uint32_t current_char,
static constexpr uint32_t kTrue = 1;
static constexpr uint32_t kFalse = 0;
ByteArray ranges = ByteArray::cast(Object(raw_byte_array));
DCHECK_EQ(ranges.length() % kUInt16Size, 0); // uc16 elements.
const int length = ranges.length() / kUInt16Size;
DCHECK_GE(length, 1);
FixedUInt16Array ranges = FixedUInt16Array::cast(Object(raw_byte_array));
DCHECK_GE(ranges.length(), 1);
// Shortcut for fully out of range chars.
if (current_char < ranges.get_uint16(0)) return kFalse;
if (current_char >= ranges.get_uint16(length - 1)) {
if (current_char < ranges.get(0)) return kFalse;
if (current_char >= ranges.get(ranges.length() - 1)) {
// The last range may be open-ended.
return (length % 2) == 0 ? kFalse : kTrue;
return (ranges.length() % 2) == 0 ? kFalse : kTrue;
}
// Binary search for the matching range. `ranges` is encoded as
// [from0, to0, from1, to1, ..., fromN, toN], or
// [from0, to0, from1, to1, ..., fromN] (open-ended last interval).
int mid, lower = 0, upper = length;
int mid, lower = 0, upper = ranges.length();
do {
mid = lower + (upper - lower) / 2;
const base::uc16 elem = ranges.get_uint16(mid);
const base::uc16 elem = ranges.get(mid);
if (current_char < elem) {
upper = mid;
} else if (current_char > elem) {
......@@ -220,7 +216,7 @@ uint32_t RegExpMacroAssembler::IsCharacterInRangeArray(uint32_t current_char,
}
} while (lower < upper);
const bool current_char_ge_last_elem = current_char >= ranges.get_uint16(mid);
const bool current_char_ge_last_elem = current_char >= ranges.get(mid);
const int current_range_start_index =
current_char_ge_last_elem ? mid : mid - 1;
......
......@@ -6,6 +6,7 @@
#define V8_REGEXP_REGEXP_MACRO_ASSEMBLER_H_
#include "src/base/strings.h"
#include "src/objects/fixed-array.h"
#include "src/regexp/regexp-ast.h"
#include "src/regexp/regexp.h"
......@@ -351,7 +352,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
const byte* input_end, int* output, int output_size,
Isolate* isolate, JSRegExp regexp);
ZoneUnorderedMap<uint32_t, Handle<ByteArray>> range_array_cache_;
ZoneUnorderedMap<uint32_t, Handle<FixedUInt16Array>> range_array_cache_;
};
} // namespace internal
......
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