11cb0ef41Sopenharmony_ci#ifndef SRC_ALIASED_BUFFER_H_
21cb0ef41Sopenharmony_ci#define SRC_ALIASED_BUFFER_H_
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#include <cinttypes>
71cb0ef41Sopenharmony_ci#include "memory_tracker.h"
81cb0ef41Sopenharmony_ci#include "v8.h"
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cinamespace node {
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_citypedef size_t AliasedBufferIndex;
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci/**
151cb0ef41Sopenharmony_ci * Do not use this class directly when creating instances of it - use the
161cb0ef41Sopenharmony_ci * Aliased*Array defined at the end of this file instead.
171cb0ef41Sopenharmony_ci *
181cb0ef41Sopenharmony_ci * This class encapsulates the technique of having a native buffer mapped to
191cb0ef41Sopenharmony_ci * a JS object. Writes to the native buffer can happen efficiently without
201cb0ef41Sopenharmony_ci * going through JS, and the data is then available to user's via the exposed
211cb0ef41Sopenharmony_ci * JS object.
221cb0ef41Sopenharmony_ci *
231cb0ef41Sopenharmony_ci * While this technique is computationally efficient, it is effectively a
241cb0ef41Sopenharmony_ci * write to JS program state w/out going through the standard
251cb0ef41Sopenharmony_ci * (monitored) API. Thus any VM capabilities to detect the modification are
261cb0ef41Sopenharmony_ci * circumvented.
271cb0ef41Sopenharmony_ci *
281cb0ef41Sopenharmony_ci * The encapsulation herein provides a placeholder where such writes can be
291cb0ef41Sopenharmony_ci * observed. Any notification APIs will be left as a future exercise.
301cb0ef41Sopenharmony_ci */
311cb0ef41Sopenharmony_citemplate <class NativeT, class V8T>
321cb0ef41Sopenharmony_ciclass AliasedBufferBase : public MemoryRetainer {
331cb0ef41Sopenharmony_ci public:
341cb0ef41Sopenharmony_ci  static_assert(std::is_scalar<NativeT>::value);
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  AliasedBufferBase(v8::Isolate* isolate,
371cb0ef41Sopenharmony_ci                    const size_t count,
381cb0ef41Sopenharmony_ci                    const AliasedBufferIndex* index = nullptr);
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  /**
411cb0ef41Sopenharmony_ci   * Create an AliasedBufferBase over a sub-region of another aliased buffer.
421cb0ef41Sopenharmony_ci   * The two will share a v8::ArrayBuffer instance &
431cb0ef41Sopenharmony_ci   * a native buffer, but will each read/write to different sections of the
441cb0ef41Sopenharmony_ci   * native buffer.
451cb0ef41Sopenharmony_ci   *
461cb0ef41Sopenharmony_ci   *  Note that byte_offset must by aligned by sizeof(NativeT).
471cb0ef41Sopenharmony_ci   */
481cb0ef41Sopenharmony_ci  // TODO(refack): refactor into a non-owning `AliasedBufferBaseView`
491cb0ef41Sopenharmony_ci  AliasedBufferBase(
501cb0ef41Sopenharmony_ci      v8::Isolate* isolate,
511cb0ef41Sopenharmony_ci      const size_t byte_offset,
521cb0ef41Sopenharmony_ci      const size_t count,
531cb0ef41Sopenharmony_ci      const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer,
541cb0ef41Sopenharmony_ci      const AliasedBufferIndex* index = nullptr);
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  AliasedBufferBase(const AliasedBufferBase& that);
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  AliasedBufferIndex Serialize(v8::Local<v8::Context> context,
591cb0ef41Sopenharmony_ci                               v8::SnapshotCreator* creator);
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  inline void Deserialize(v8::Local<v8::Context> context);
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  AliasedBufferBase& operator=(AliasedBufferBase&& that) noexcept;
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  /**
661cb0ef41Sopenharmony_ci   * Helper class that is returned from operator[] to support assignment into
671cb0ef41Sopenharmony_ci   * a specified location.
681cb0ef41Sopenharmony_ci   */
691cb0ef41Sopenharmony_ci  class Reference {
701cb0ef41Sopenharmony_ci   public:
711cb0ef41Sopenharmony_ci    Reference(AliasedBufferBase<NativeT, V8T>* aliased_buffer, size_t index)
721cb0ef41Sopenharmony_ci        : aliased_buffer_(aliased_buffer), index_(index) {}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci    Reference(const Reference& that)
751cb0ef41Sopenharmony_ci        : aliased_buffer_(that.aliased_buffer_),
761cb0ef41Sopenharmony_ci          index_(that.index_) {
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    inline Reference& operator=(const NativeT& val) {
801cb0ef41Sopenharmony_ci      aliased_buffer_->SetValue(index_, val);
811cb0ef41Sopenharmony_ci      return *this;
821cb0ef41Sopenharmony_ci    }
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci    inline Reference& operator=(const Reference& val) {
851cb0ef41Sopenharmony_ci      return *this = static_cast<NativeT>(val);
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci    operator NativeT() const {
891cb0ef41Sopenharmony_ci      return aliased_buffer_->GetValue(index_);
901cb0ef41Sopenharmony_ci    }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci    inline Reference& operator+=(const NativeT& val) {
931cb0ef41Sopenharmony_ci      const NativeT current = aliased_buffer_->GetValue(index_);
941cb0ef41Sopenharmony_ci      aliased_buffer_->SetValue(index_, current + val);
951cb0ef41Sopenharmony_ci      return *this;
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci    inline Reference& operator+=(const Reference& val) {
991cb0ef41Sopenharmony_ci      return this->operator+=(static_cast<NativeT>(val));
1001cb0ef41Sopenharmony_ci    }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    inline Reference& operator-=(const NativeT& val) {
1031cb0ef41Sopenharmony_ci      const NativeT current = aliased_buffer_->GetValue(index_);
1041cb0ef41Sopenharmony_ci      aliased_buffer_->SetValue(index_, current - val);
1051cb0ef41Sopenharmony_ci      return *this;
1061cb0ef41Sopenharmony_ci    }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci   private:
1091cb0ef41Sopenharmony_ci    AliasedBufferBase<NativeT, V8T>* aliased_buffer_;
1101cb0ef41Sopenharmony_ci    size_t index_;
1111cb0ef41Sopenharmony_ci  };
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  /**
1141cb0ef41Sopenharmony_ci   *  Get the underlying v8 TypedArray overlayed on top of the native buffer
1151cb0ef41Sopenharmony_ci   */
1161cb0ef41Sopenharmony_ci  v8::Local<V8T> GetJSArray() const;
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  void Release();
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  /**
1211cb0ef41Sopenharmony_ci  *  Get the underlying v8::ArrayBuffer underlying the TypedArray and
1221cb0ef41Sopenharmony_ci  *  overlaying the native buffer
1231cb0ef41Sopenharmony_ci  */
1241cb0ef41Sopenharmony_ci  v8::Local<v8::ArrayBuffer> GetArrayBuffer() const;
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  /**
1271cb0ef41Sopenharmony_ci   *  Get the underlying native buffer. Note that all reads/writes should occur
1281cb0ef41Sopenharmony_ci   *  through the GetValue/SetValue/operator[] methods
1291cb0ef41Sopenharmony_ci   */
1301cb0ef41Sopenharmony_ci  inline const NativeT* GetNativeBuffer() const;
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  /**
1331cb0ef41Sopenharmony_ci   *  Synonym for GetBuffer()
1341cb0ef41Sopenharmony_ci   */
1351cb0ef41Sopenharmony_ci  inline const NativeT* operator*() const;
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  /**
1381cb0ef41Sopenharmony_ci   *  Set position index to given value.
1391cb0ef41Sopenharmony_ci   */
1401cb0ef41Sopenharmony_ci  inline void SetValue(const size_t index, NativeT value);
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  /**
1431cb0ef41Sopenharmony_ci   *  Get value at position index
1441cb0ef41Sopenharmony_ci   */
1451cb0ef41Sopenharmony_ci  inline const NativeT GetValue(const size_t index) const;
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  /**
1481cb0ef41Sopenharmony_ci   *  Effectively, a synonym for GetValue/SetValue
1491cb0ef41Sopenharmony_ci   */
1501cb0ef41Sopenharmony_ci  Reference operator[](size_t index);
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  NativeT operator[](size_t index) const;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  size_t Length() const;
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  // Should only be used to extend the array.
1571cb0ef41Sopenharmony_ci  // Should only be used on an owning array, not one created as a sub array of
1581cb0ef41Sopenharmony_ci  // an owning `AliasedBufferBase`.
1591cb0ef41Sopenharmony_ci  void reserve(size_t new_capacity);
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  inline size_t SelfSize() const override;
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  inline const char* MemoryInfoName() const override;
1641cb0ef41Sopenharmony_ci  inline void MemoryInfo(node::MemoryTracker* tracker) const override;
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci private:
1671cb0ef41Sopenharmony_ci  v8::Isolate* isolate_ = nullptr;
1681cb0ef41Sopenharmony_ci  size_t count_ = 0;
1691cb0ef41Sopenharmony_ci  size_t byte_offset_ = 0;
1701cb0ef41Sopenharmony_ci  NativeT* buffer_ = nullptr;
1711cb0ef41Sopenharmony_ci  v8::Global<V8T> js_array_;
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  // Deserialize data
1741cb0ef41Sopenharmony_ci  const AliasedBufferIndex* index_ = nullptr;
1751cb0ef41Sopenharmony_ci};
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci#define ALIASED_BUFFER_LIST(V)                                                 \
1781cb0ef41Sopenharmony_ci  V(int8_t, Int8Array)                                                         \
1791cb0ef41Sopenharmony_ci  V(uint8_t, Uint8Array)                                                       \
1801cb0ef41Sopenharmony_ci  V(int16_t, Int16Array)                                                       \
1811cb0ef41Sopenharmony_ci  V(uint16_t, Uint16Array)                                                     \
1821cb0ef41Sopenharmony_ci  V(int32_t, Int32Array)                                                       \
1831cb0ef41Sopenharmony_ci  V(uint32_t, Uint32Array)                                                     \
1841cb0ef41Sopenharmony_ci  V(float, Float32Array)                                                       \
1851cb0ef41Sopenharmony_ci  V(double, Float64Array)                                                      \
1861cb0ef41Sopenharmony_ci  V(int64_t, BigInt64Array)
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci#define V(NativeT, V8T)                                                        \
1891cb0ef41Sopenharmony_ci  typedef AliasedBufferBase<NativeT, v8::V8T> Aliased##V8T;
1901cb0ef41Sopenharmony_ciALIASED_BUFFER_LIST(V)
1911cb0ef41Sopenharmony_ci#undef V
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci}  // namespace node
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci#endif  // SRC_ALIASED_BUFFER_H_
198