summaryrefslogtreecommitdiff
path: root/deps/v8/src/utils
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2021-02-11 19:03:35 +0100
committerMichaël Zasso <targos@protonmail.com>2021-02-11 19:09:18 +0100
commitc7b329225126ad3b9eeb2408e0f0801f1aea5eb1 (patch)
tree193c193111d5f302031ad345bc94d17a3f67bf66 /deps/v8/src/utils
parent6ea9af9906cd74ed07ca05cf6aa44382025a6044 (diff)
downloadnode-new-c7b329225126ad3b9eeb2408e0f0801f1aea5eb1.tar.gz
deps: update V8 to 8.8.278.17
PR-URL: https://github.com/nodejs/node/pull/36139 Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Shelley Vohr <codebytere@gmail.com>
Diffstat (limited to 'deps/v8/src/utils')
-rw-r--r--deps/v8/src/utils/DIR_METADATA11
-rw-r--r--deps/v8/src/utils/OWNERS2
-rw-r--r--deps/v8/src/utils/bit-vector.cc2
-rw-r--r--deps/v8/src/utils/bit-vector.h2
-rw-r--r--deps/v8/src/utils/identity-map.cc144
-rw-r--r--deps/v8/src/utils/identity-map.h71
-rw-r--r--deps/v8/src/utils/locked-queue-inl.h6
-rw-r--r--deps/v8/src/utils/locked-queue.h2
-rw-r--r--deps/v8/src/utils/utils.h73
9 files changed, 221 insertions, 92 deletions
diff --git a/deps/v8/src/utils/DIR_METADATA b/deps/v8/src/utils/DIR_METADATA
new file mode 100644
index 0000000000..2f8dbbcf45
--- /dev/null
+++ b/deps/v8/src/utils/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+# https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+ component: "Blink>JavaScript"
+} \ No newline at end of file
diff --git a/deps/v8/src/utils/OWNERS b/deps/v8/src/utils/OWNERS
index 4750620072..48d72aea5e 100644
--- a/deps/v8/src/utils/OWNERS
+++ b/deps/v8/src/utils/OWNERS
@@ -1,3 +1 @@
file:../../COMMON_OWNERS
-
-# COMPONENT: Blink>JavaScript
diff --git a/deps/v8/src/utils/bit-vector.cc b/deps/v8/src/utils/bit-vector.cc
index 20e645f24c..f90175189b 100644
--- a/deps/v8/src/utils/bit-vector.cc
+++ b/deps/v8/src/utils/bit-vector.cc
@@ -11,7 +11,7 @@ namespace v8 {
namespace internal {
#ifdef DEBUG
-void BitVector::Print() {
+void BitVector::Print() const {
bool first = true;
PrintF("{");
for (int i = 0; i < length(); i++) {
diff --git a/deps/v8/src/utils/bit-vector.h b/deps/v8/src/utils/bit-vector.h
index d68009d723..c171f51160 100644
--- a/deps/v8/src/utils/bit-vector.h
+++ b/deps/v8/src/utils/bit-vector.h
@@ -277,7 +277,7 @@ class V8_EXPORT_PRIVATE BitVector : public ZoneObject {
int length() const { return length_; }
#ifdef DEBUG
- void Print();
+ void Print() const;
#endif
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(BitVector);
diff --git a/deps/v8/src/utils/identity-map.cc b/deps/v8/src/utils/identity-map.cc
index 909c175007..6e22cc783a 100644
--- a/deps/v8/src/utils/identity-map.cc
+++ b/deps/v8/src/utils/identity-map.cc
@@ -26,7 +26,7 @@ void IdentityMapBase::Clear() {
DCHECK(!is_iterable());
DCHECK_NOT_NULL(strong_roots_entry_);
heap_->UnregisterStrongRoots(strong_roots_entry_);
- DeletePointerArray(reinterpret_cast<void**>(keys_), capacity_);
+ DeletePointerArray(reinterpret_cast<uintptr_t*>(keys_), capacity_);
DeletePointerArray(values_, capacity_);
keys_ = nullptr;
strong_roots_entry_ = nullptr;
@@ -47,8 +47,8 @@ void IdentityMapBase::DisableIteration() {
is_iterable_ = false;
}
-int IdentityMapBase::ScanKeysFor(Address address) const {
- int start = Hash(address) & mask_;
+int IdentityMapBase::ScanKeysFor(Address address, uint32_t hash) const {
+ int start = hash & mask_;
Address not_mapped = ReadOnlyRoots(heap_).not_mapped_symbol().ptr();
for (int index = start; index < capacity_; index++) {
if (keys_[index] == address) return index; // Found.
@@ -61,33 +61,41 @@ int IdentityMapBase::ScanKeysFor(Address address) const {
return -1;
}
-int IdentityMapBase::InsertKey(Address address) {
+std::pair<int, bool> IdentityMapBase::InsertKey(Address address,
+ uint32_t hash) {
+ DCHECK_EQ(gc_counter_, heap_->gc_count());
+
+ // Grow the map if we reached >= 80% occupancy.
+ if (size_ + size_ / 4 >= capacity_) {
+ Resize(capacity_ * kResizeFactor);
+ }
+
Address not_mapped = ReadOnlyRoots(heap_).not_mapped_symbol().ptr();
+
+ int start = hash & mask_;
+ // Guaranteed to terminate since size_ < capacity_, there must be at least
+ // one empty slot.
+ int index = start;
while (true) {
- int start = Hash(address) & mask_;
- int limit = capacity_ / 2;
- // Search up to {limit} entries.
- for (int index = start; --limit > 0; index = (index + 1) & mask_) {
- if (keys_[index] == address) return index; // Found.
- if (keys_[index] == not_mapped) { // Free entry.
- size_++;
- DCHECK_LE(size_, capacity_);
- keys_[index] = address;
- return index;
- }
+ if (keys_[index] == address) return {index, true}; // Found.
+ if (keys_[index] == not_mapped) { // Free entry.
+ size_++;
+ DCHECK_LE(size_, capacity_);
+ keys_[index] = address;
+ return {index, false};
}
- // Should only have to resize once, since we grow 4x.
- Resize(capacity_ * kResizeFactor);
+ index = (index + 1) & mask_;
+ // We should never loop back to the start.
+ DCHECK_NE(index, start);
}
- UNREACHABLE();
}
-bool IdentityMapBase::DeleteIndex(int index, void** deleted_value) {
+bool IdentityMapBase::DeleteIndex(int index, uintptr_t* deleted_value) {
if (deleted_value != nullptr) *deleted_value = values_[index];
Address not_mapped = ReadOnlyRoots(heap_).not_mapped_symbol().ptr();
DCHECK_NE(keys_[index], not_mapped);
keys_[index] = not_mapped;
- values_[index] = nullptr;
+ values_[index] = 0;
size_--;
DCHECK_GE(size_, 0);
@@ -113,7 +121,7 @@ bool IdentityMapBase::DeleteIndex(int index, void** deleted_value) {
}
DCHECK_EQ(not_mapped, keys_[index]);
- DCHECK_NULL(values_[index]);
+ DCHECK_EQ(values_[index], 0);
std::swap(keys_[index], keys_[next_index]);
std::swap(values_[index], values_[next_index]);
index = next_index;
@@ -123,39 +131,69 @@ bool IdentityMapBase::DeleteIndex(int index, void** deleted_value) {
}
int IdentityMapBase::Lookup(Address key) const {
- int index = ScanKeysFor(key);
+ uint32_t hash = Hash(key);
+ int index = ScanKeysFor(key, hash);
if (index < 0 && gc_counter_ != heap_->gc_count()) {
// Miss; rehash if there was a GC, then lookup again.
const_cast<IdentityMapBase*>(this)->Rehash();
- index = ScanKeysFor(key);
+ index = ScanKeysFor(key, hash);
}
return index;
}
-int IdentityMapBase::LookupOrInsert(Address key) {
+std::pair<int, bool> IdentityMapBase::LookupOrInsert(Address key) {
+ uint32_t hash = Hash(key);
// Perform an optimistic lookup.
- int index = ScanKeysFor(key);
+ int index = ScanKeysFor(key, hash);
+ bool already_exists;
if (index < 0) {
// Miss; rehash if there was a GC, then insert.
if (gc_counter_ != heap_->gc_count()) Rehash();
- index = InsertKey(key);
+ std::tie(index, already_exists) = InsertKey(key, hash);
+ } else {
+ already_exists = true;
}
DCHECK_GE(index, 0);
- return index;
+ return {index, already_exists};
}
-int IdentityMapBase::Hash(Address address) const {
+uint32_t IdentityMapBase::Hash(Address address) const {
CHECK_NE(address, ReadOnlyRoots(heap_).not_mapped_symbol().ptr());
- return static_cast<int>(hasher_(address));
+ return static_cast<uint32_t>(hasher_(address));
}
// Searches this map for the given key using the object's address
// as the identity, returning:
-// found => a pointer to the storage location for the value
-// not found => a pointer to a new storage location for the value
-IdentityMapBase::RawEntry IdentityMapBase::GetEntry(Address key) {
+// found => a pointer to the storage location for the value, true
+// not found => a pointer to a new storage location for the value, false
+IdentityMapFindResult<uintptr_t> IdentityMapBase::FindOrInsertEntry(
+ Address key) {
CHECK(!is_iterable()); // Don't allow insertion while iterable.
if (capacity_ == 0) {
+ return {InsertEntry(key), false};
+ }
+ auto lookup_result = LookupOrInsert(key);
+ return {&values_[lookup_result.first], lookup_result.second};
+}
+
+// Searches this map for the given key using the object's address
+// as the identity, returning:
+// found => a pointer to the storage location for the value
+// not found => {nullptr}
+IdentityMapBase::RawEntry IdentityMapBase::FindEntry(Address key) const {
+ // Don't allow find by key while iterable (might rehash).
+ CHECK(!is_iterable());
+ if (size_ == 0) return nullptr;
+ int index = Lookup(key);
+ return index >= 0 ? &values_[index] : nullptr;
+}
+
+// Inserts the given key using the object's address as the identity, returning
+// a pointer to the new storage location for the value.
+IdentityMapBase::RawEntry IdentityMapBase::InsertEntry(Address key) {
+ // Don't allow find by key while iterable (might rehash).
+ CHECK(!is_iterable());
+ if (capacity_ == 0) {
// Allocate the initial storage for keys and values.
capacity_ = kInitialIdentityMapSize;
mask_ = kInitialIdentityMapSize - 1;
@@ -165,32 +203,26 @@ IdentityMapBase::RawEntry IdentityMapBase::GetEntry(Address key) {
Address not_mapped = ReadOnlyRoots(heap_).not_mapped_symbol().ptr();
for (int i = 0; i < capacity_; i++) keys_[i] = not_mapped;
values_ = NewPointerArray(capacity_);
- memset(values_, 0, sizeof(void*) * capacity_);
+ memset(values_, 0, sizeof(uintptr_t) * capacity_);
strong_roots_entry_ = heap_->RegisterStrongRoots(
FullObjectSlot(keys_), FullObjectSlot(keys_ + capacity_));
+ } else {
+ // Rehash if there was a GC, then insert.
+ if (gc_counter_ != heap_->gc_count()) Rehash();
}
- int index = LookupOrInsert(key);
- return &values_[index];
-}
-// Searches this map for the given key using the object's address
-// as the identity, returning:
-// found => a pointer to the storage location for the value
-// not found => {nullptr}
-IdentityMapBase::RawEntry IdentityMapBase::FindEntry(Address key) const {
- // Don't allow find by key while iterable (might rehash).
- CHECK(!is_iterable());
- if (size_ == 0) return nullptr;
- // Remove constness since lookup might have to rehash.
- int index = Lookup(key);
- return index >= 0 ? &values_[index] : nullptr;
+ int index;
+ bool already_exists;
+ std::tie(index, already_exists) = InsertKey(key, Hash(key));
+ DCHECK(!already_exists);
+ return &values_[index];
}
// Deletes the given key from the map using the object's address as the
// identity, returning true iff the key was found (in which case, the value
// argument will be set to the deleted entry's value).
-bool IdentityMapBase::DeleteEntry(Address key, void** deleted_value) {
+bool IdentityMapBase::DeleteEntry(Address key, uintptr_t* deleted_value) {
CHECK(!is_iterable()); // Don't allow deletion by key while iterable.
if (size_ == 0) return false;
int index = Lookup(key);
@@ -232,7 +264,7 @@ void IdentityMapBase::Rehash() {
// Record the current GC counter.
gc_counter_ = heap_->gc_count();
// Assume that most objects won't be moved.
- std::vector<std::pair<Address, void*>> reinsert;
+ std::vector<std::pair<Address, uintptr_t>> reinsert;
// Search the table looking for keys that wouldn't be found with their
// current hashcode and evacuate them.
int last_empty = -1;
@@ -244,9 +276,9 @@ void IdentityMapBase::Rehash() {
int pos = Hash(keys_[i]) & mask_;
if (pos <= last_empty || pos > i) {
// Evacuate an entry that is in the wrong place.
- reinsert.push_back(std::pair<Address, void*>(keys_[i], values_[i]));
+ reinsert.push_back(std::pair<Address, uintptr_t>(keys_[i], values_[i]));
keys_[i] = not_mapped;
- values_[i] = nullptr;
+ values_[i] = 0;
last_empty = i;
size_--;
}
@@ -254,7 +286,7 @@ void IdentityMapBase::Rehash() {
}
// Reinsert all the key/value pairs that were in the wrong place.
for (auto pair : reinsert) {
- int index = InsertKey(pair.first);
+ int index = InsertKey(pair.first, Hash(pair.first)).first;
DCHECK_GE(index, 0);
values_[index] = pair.second;
}
@@ -266,7 +298,7 @@ void IdentityMapBase::Resize(int new_capacity) {
DCHECK_GT(new_capacity, size_);
int old_capacity = capacity_;
Address* old_keys = keys_;
- void** old_values = values_;
+ uintptr_t* old_values = values_;
capacity_ = new_capacity;
mask_ = capacity_ - 1;
@@ -277,11 +309,11 @@ void IdentityMapBase::Resize(int new_capacity) {
Address not_mapped = ReadOnlyRoots(heap_).not_mapped_symbol().ptr();
for (int i = 0; i < capacity_; i++) keys_[i] = not_mapped;
values_ = NewPointerArray(capacity_);
- memset(values_, 0, sizeof(void*) * capacity_);
+ memset(values_, 0, sizeof(uintptr_t) * capacity_);
for (int i = 0; i < old_capacity; i++) {
if (old_keys[i] == not_mapped) continue;
- int index = InsertKey(old_keys[i]);
+ int index = InsertKey(old_keys[i], Hash(old_keys[i])).first;
DCHECK_GE(index, 0);
values_[index] = old_values[i];
}
@@ -292,7 +324,7 @@ void IdentityMapBase::Resize(int new_capacity) {
FullObjectSlot(keys_ + capacity_));
// Delete old storage;
- DeletePointerArray(reinterpret_cast<void**>(old_keys), old_capacity);
+ DeletePointerArray(reinterpret_cast<uintptr_t*>(old_keys), old_capacity);
DeletePointerArray(old_values, old_capacity);
}
diff --git a/deps/v8/src/utils/identity-map.h b/deps/v8/src/utils/identity-map.h
index 362a3decfa..20b5f100bf 100644
--- a/deps/v8/src/utils/identity-map.h
+++ b/deps/v8/src/utils/identity-map.h
@@ -5,6 +5,8 @@
#ifndef V8_UTILS_IDENTITY_MAP_H_
#define V8_UTILS_IDENTITY_MAP_H_
+#include <type_traits>
+
#include "src/base/functional.h"
#include "src/handles/handles.h"
#include "src/objects/heap-object.h"
@@ -16,6 +18,12 @@ namespace internal {
class Heap;
class StrongRootsEntry;
+template <typename T>
+struct IdentityMapFindResult {
+ T* entry;
+ bool already_exists;
+};
+
// Base class of identity maps contains shared code for all template
// instantions.
class V8_EXPORT_PRIVATE IdentityMapBase {
@@ -30,7 +38,7 @@ class V8_EXPORT_PRIVATE IdentityMapBase {
// within the {keys_} array in order to simulate a moving GC.
friend class IdentityMapTester;
- using RawEntry = void**;
+ using RawEntry = uintptr_t*;
explicit IdentityMapBase(Heap* heap)
: heap_(heap),
@@ -44,9 +52,10 @@ class V8_EXPORT_PRIVATE IdentityMapBase {
is_iterable_(false) {}
virtual ~IdentityMapBase();
- RawEntry GetEntry(Address key);
+ IdentityMapFindResult<uintptr_t> FindOrInsertEntry(Address key);
RawEntry FindEntry(Address key) const;
- bool DeleteEntry(Address key, void** deleted_value);
+ RawEntry InsertEntry(Address key);
+ bool DeleteEntry(Address key, uintptr_t* deleted_value);
void Clear();
Address KeyAtIndex(int index) const;
@@ -57,19 +66,19 @@ class V8_EXPORT_PRIVATE IdentityMapBase {
void EnableIteration();
void DisableIteration();
- virtual void** NewPointerArray(size_t length) = 0;
- virtual void DeletePointerArray(void** array, size_t length) = 0;
+ virtual uintptr_t* NewPointerArray(size_t length) = 0;
+ virtual void DeletePointerArray(uintptr_t* array, size_t length) = 0;
private:
// Internal implementation should not be called directly by subclasses.
- int ScanKeysFor(Address address) const;
- int InsertKey(Address address);
+ int ScanKeysFor(Address address, uint32_t hash) const;
+ std::pair<int, bool> InsertKey(Address address, uint32_t hash);
int Lookup(Address key) const;
- int LookupOrInsert(Address key);
- bool DeleteIndex(int index, void** deleted_value);
+ std::pair<int, bool> LookupOrInsert(Address key);
+ bool DeleteIndex(int index, uintptr_t* deleted_value);
void Rehash();
void Resize(int new_capacity);
- int Hash(Address address) const;
+ uint32_t Hash(Address address) const;
base::hash<uintptr_t> hasher_;
Heap* heap_;
@@ -79,7 +88,7 @@ class V8_EXPORT_PRIVATE IdentityMapBase {
int mask_;
Address* keys_;
StrongRootsEntry* strong_roots_entry_;
- void** values_;
+ uintptr_t* values_;
bool is_iterable_;
DISALLOW_COPY_AND_ASSIGN(IdentityMapBase);
@@ -89,11 +98,15 @@ class V8_EXPORT_PRIVATE IdentityMapBase {
// The map is robust w.r.t. garbage collection by synchronization with the
// supplied {heap}.
// * Keys are treated as strong roots.
-// * The value type {V} must be reinterpret_cast'able to {void*}
+// * The value type {V} must be reinterpret_cast'able to {uintptr_t}
// * The value type {V} must not be a heap type.
template <typename V, class AllocationPolicy>
class IdentityMap : public IdentityMapBase {
public:
+ STATIC_ASSERT(sizeof(V) <= sizeof(uintptr_t));
+ STATIC_ASSERT(std::is_trivially_copyable<V>::value);
+ STATIC_ASSERT(std::is_trivially_destructible<V>::value);
+
explicit IdentityMap(Heap* heap,
AllocationPolicy allocator = AllocationPolicy())
: IdentityMapBase(heap), allocator_(allocator) {}
@@ -101,10 +114,15 @@ class IdentityMap : public IdentityMapBase {
// Searches this map for the given key using the object's address
// as the identity, returning:
- // found => a pointer to the storage location for the value
- // not found => a pointer to a new storage location for the value
- V* Get(Handle<Object> key) { return Get(*key); }
- V* Get(Object key) { return reinterpret_cast<V*>(GetEntry(key.ptr())); }
+ // found => a pointer to the storage location for the value, true
+ // not found => a pointer to a new storage location for the value, false
+ IdentityMapFindResult<V> FindOrInsert(Handle<Object> key) {
+ return FindOrInsert(*key);
+ }
+ IdentityMapFindResult<V> FindOrInsert(Object key) {
+ auto raw = FindOrInsertEntry(key.ptr());
+ return {reinterpret_cast<V*>(raw.entry), raw.already_exists};
+ }
// Searches this map for the given key using the object's address
// as the identity, returning:
@@ -115,17 +133,18 @@ class IdentityMap : public IdentityMapBase {
return reinterpret_cast<V*>(FindEntry(key.ptr()));
}
- // Set the value for the given key.
- void Set(Handle<Object> key, V v) { Set(*key, v); }
- void Set(Object key, V v) {
- *(reinterpret_cast<V*>(GetEntry(key.ptr()))) = v;
+ // Insert the value for the given key. The key must not have previously
+ // existed.
+ void Insert(Handle<Object> key, V v) { Insert(*key, v); }
+ void Insert(Object key, V v) {
+ *reinterpret_cast<V*>(InsertEntry(key.ptr())) = v;
}
bool Delete(Handle<Object> key, V* deleted_value) {
return Delete(*key, deleted_value);
}
bool Delete(Object key, V* deleted_value) {
- void* v = nullptr;
+ uintptr_t v;
bool deleted_something = DeleteEntry(key.ptr(), &v);
if (deleted_value != nullptr && deleted_something) {
*deleted_value = *reinterpret_cast<V*>(&v);
@@ -188,12 +207,12 @@ class IdentityMap : public IdentityMapBase {
// TODO(ishell): consider removing virtual methods in favor of combining
// IdentityMapBase and IdentityMap into one class. This would also save
- // space when sizeof(V) is less than sizeof(void*).
- void** NewPointerArray(size_t length) override {
- return allocator_.template NewArray<void*, Buffer>(length);
+ // space when sizeof(V) is less than sizeof(uintptr_t).
+ uintptr_t* NewPointerArray(size_t length) override {
+ return allocator_.template NewArray<uintptr_t, Buffer>(length);
}
- void DeletePointerArray(void** array, size_t length) override {
- allocator_.template DeleteArray<void*, Buffer>(array, length);
+ void DeletePointerArray(uintptr_t* array, size_t length) override {
+ allocator_.template DeleteArray<uintptr_t, Buffer>(array, length);
}
private:
diff --git a/deps/v8/src/utils/locked-queue-inl.h b/deps/v8/src/utils/locked-queue-inl.h
index 9416dd7d37..edcdf03a5d 100644
--- a/deps/v8/src/utils/locked-queue-inl.h
+++ b/deps/v8/src/utils/locked-queue-inl.h
@@ -38,10 +38,10 @@ inline LockedQueue<Record>::~LockedQueue() {
}
template <typename Record>
-inline void LockedQueue<Record>::Enqueue(const Record& record) {
+inline void LockedQueue<Record>::Enqueue(Record record) {
Node* n = new Node();
CHECK_NOT_NULL(n);
- n->value = record;
+ n->value = std::move(record);
{
base::MutexGuard guard(&tail_mutex_);
tail_->next.SetValue(n);
@@ -57,7 +57,7 @@ inline bool LockedQueue<Record>::Dequeue(Record* record) {
old_head = head_;
Node* const next_node = head_->next.Value();
if (next_node == nullptr) return false;
- *record = next_node->value;
+ *record = std::move(next_node->value);
head_ = next_node;
}
delete old_head;
diff --git a/deps/v8/src/utils/locked-queue.h b/deps/v8/src/utils/locked-queue.h
index 4dd6488184..7594cc93c3 100644
--- a/deps/v8/src/utils/locked-queue.h
+++ b/deps/v8/src/utils/locked-queue.h
@@ -21,7 +21,7 @@ class LockedQueue final {
public:
inline LockedQueue();
inline ~LockedQueue();
- inline void Enqueue(const Record& record);
+ inline void Enqueue(Record record);
inline bool Dequeue(Record* record);
inline bool IsEmpty() const;
inline bool Peek(Record* record) const;
diff --git a/deps/v8/src/utils/utils.h b/deps/v8/src/utils/utils.h
index 7ec0dd2c00..af8f34030f 100644
--- a/deps/v8/src/utils/utils.h
+++ b/deps/v8/src/utils/utils.h
@@ -69,13 +69,13 @@ static T ArithmeticShiftRight(T x, int shift) {
// Returns the maximum of the two parameters.
template <typename T>
constexpr T Max(T a, T b) {
- return a < b ? b : a;
+ return std::max(a, b);
}
// Returns the minimum of the two parameters.
template <typename T>
constexpr T Min(T a, T b) {
- return a < b ? a : b;
+ return std::min(a, b);
}
// Returns the maximum of the two parameters according to JavaScript semantics.
@@ -135,6 +135,15 @@ inline double Modulo(double x, double y) {
}
template <typename T>
+T Saturate(int64_t value) {
+ static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller");
+ int64_t min = static_cast<int64_t>(std::numeric_limits<T>::min());
+ int64_t max = static_cast<int64_t>(std::numeric_limits<T>::max());
+ int64_t clamped = std::max(min, std::min(max, value));
+ return static_cast<T>(clamped);
+}
+
+template <typename T>
T SaturateAdd(T a, T b) {
if (std::is_signed<T>::value) {
if (a > 0 && b > 0) {
@@ -176,6 +185,53 @@ T SaturateSub(T a, T b) {
return a - b;
}
+template <typename T>
+T SaturateRoundingQMul(T a, T b) {
+ // Saturating rounding multiplication for Q-format numbers. See
+ // https://en.wikipedia.org/wiki/Q_(number_format) for a description.
+ // Specifically this supports Q7, Q15, and Q31. This follows the
+ // implementation in simulator-logic-arm64.cc (sqrdmulh) to avoid overflow
+ // when a == b == int32 min.
+ static_assert(std::is_integral<T>::value, "only integral types");
+
+ constexpr int size_in_bits = sizeof(T) * 8;
+ int round_const = 1 << (size_in_bits - 2);
+ int64_t product = a * b;
+ product += round_const;
+ product >>= (size_in_bits - 1);
+ return Saturate<T>(product);
+}
+
+// Multiply two numbers, returning a result that is twice as wide, no overflow.
+// Put Wide first so we can use function template argument deduction for Narrow,
+// and callers can provide only Wide.
+template <typename Wide, typename Narrow>
+Wide MultiplyLong(Narrow a, Narrow b) {
+ static_assert(
+ std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
+ "only integral types");
+ static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
+ "both must have same signedness");
+ static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");
+
+ return static_cast<Wide>(a) * static_cast<Wide>(b);
+}
+
+// Add two numbers, returning a result that is twice as wide, no overflow.
+// Put Wide first so we can use function template argument deduction for Narrow,
+// and callers can provide only Wide.
+template <typename Wide, typename Narrow>
+Wide AddLong(Narrow a, Narrow b) {
+ static_assert(
+ std::is_integral<Narrow>::value && std::is_integral<Wide>::value,
+ "only integral types");
+ static_assert(std::is_signed<Narrow>::value == std::is_signed<Wide>::value,
+ "both must have same signedness");
+ static_assert(sizeof(Narrow) * 2 == sizeof(Wide), "only twice as long");
+
+ return static_cast<Wide>(a) + static_cast<Wide>(b);
+}
+
// Helper macros for defining a contiguous sequence of field offset constants.
// Example: (backslashes at the ends of respective lines of this multi-line
// macro definition are omitted here to please the compiler)
@@ -682,6 +738,19 @@ static inline V ByteReverse(V value) {
}
}
+#if V8_OS_AIX
+// glibc on aix has a bug when using ceil, trunc or nearbyint:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97086
+template <typename T>
+T FpOpWorkaround(T input, T value) {
+ if (/*if -*/ std::signbit(input) && value == 0.0 &&
+ /*if +*/ !std::signbit(value)) {
+ return -0.0;
+ }
+ return value;
+}
+#endif
+
V8_EXPORT_PRIVATE bool PassesFilter(Vector<const char> name,
Vector<const char> filter);