summaryrefslogtreecommitdiff
path: root/deps/v8/src/wasm/wasm-memory.h
blob: e0ff6ef65c9886bba3956437b5e5cedd4cddafee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_WASM_WASM_MEMORY_H_
#define V8_WASM_WASM_MEMORY_H_

#include <atomic>
#include <unordered_map>

#include "src/base/platform/mutex.h"
#include "src/flags.h"
#include "src/handles.h"
#include "src/objects/js-array.h"

namespace v8 {
namespace internal {

class Histogram;  // defined in counters.h

namespace wasm {

class WasmMemoryTracker {
 public:
  WasmMemoryTracker() {}
  ~WasmMemoryTracker();

  // ReserveAddressSpace attempts to increase the reserved address space counter
  // to determine whether there is enough headroom to allocate another guarded
  // Wasm memory. Returns true if successful (meaning it is okay to go ahead and
  // allocate the buffer), false otherwise.
  bool ReserveAddressSpace(size_t num_bytes);

  void RegisterAllocation(void* allocation_base, size_t allocation_length,
                          void* buffer_start, size_t buffer_length);

  struct AllocationData {
    void* allocation_base = nullptr;
    size_t allocation_length = 0;
    void* buffer_start = nullptr;
    size_t buffer_length = 0;

   private:
    AllocationData() = default;
    AllocationData(void* allocation_base, size_t allocation_length,
                   void* buffer_start, size_t buffer_length)
        : allocation_base(allocation_base),
          allocation_length(allocation_length),
          buffer_start(buffer_start),
          buffer_length(buffer_length) {
      DCHECK_LE(reinterpret_cast<uintptr_t>(allocation_base),
                reinterpret_cast<uintptr_t>(buffer_start));
      DCHECK_GE(
          reinterpret_cast<uintptr_t>(allocation_base) + allocation_length,
          reinterpret_cast<uintptr_t>(buffer_start));
      DCHECK_GE(
          reinterpret_cast<uintptr_t>(allocation_base) + allocation_length,
          reinterpret_cast<uintptr_t>(buffer_start) + buffer_length);
    }

    friend WasmMemoryTracker;
  };

  // Decreases the amount of reserved address space
  void ReleaseReservation(size_t num_bytes);

  // Removes an allocation from the tracker
  AllocationData ReleaseAllocation(const void* buffer_start);

  bool IsWasmMemory(const void* buffer_start);

  // Returns a pointer to a Wasm buffer's allocation data, or nullptr if the
  // buffer is not tracked.
  const AllocationData* FindAllocationData(const void* buffer_start);

  // Empty WebAssembly memories are all backed by a shared inaccessible
  // reservation. This method creates this store or returns the existing one if
  // already created.
  void* GetEmptyBackingStore(void** allocation_base, size_t* allocation_length,
                             Heap* heap);

  bool IsEmptyBackingStore(const void* buffer_start) const;

  // Checks if a buffer points to a Wasm memory and if so does any necessary
  // work to reclaim the buffer. If this function returns false, the caller must
  // free the buffer manually.
  bool FreeMemoryIfIsWasmMemory(const void* buffer_start);

  void SetAllocationResultHistogram(Histogram* allocation_result) {
    allocation_result_ = allocation_result;
  }
  void SetAddressSpaceUsageHistogram(Histogram* address_space_usage) {
    address_space_usage_mb_ = address_space_usage;
  }

  // Allocation results are reported to UMA
  //
  // See wasm_memory_allocation_result in counters.h
  enum class AllocationStatus {
    kSuccess,  // Succeeded on the first try

    kSuccessAfterRetry,  // Succeeded after garbage collection

    kAddressSpaceLimitReachedFailure,  // Failed because Wasm is at its address
                                       // space limit

    kOtherFailure  // Failed for an unknown reason
  };

  void AddAllocationStatusSample(AllocationStatus status);

 private:
  AllocationData InternalReleaseAllocation(const void* buffer_start);
  void AddAddressSpaceSample();

  // Clients use a two-part process. First they "reserve" the address space,
  // which signifies an intent to actually allocate it. This determines whether
  // doing the allocation would put us over our limit. Once there is a
  // reservation, clients can do the allocation and register the result.
  //
  // We should always have:
  // allocated_address_space_ <= reserved_address_space_ <= kAddressSpaceLimit
  std::atomic_size_t reserved_address_space_{0};

  // Used to protect access to the allocated address space counter and
  // allocation map. This is needed because Wasm memories can be freed on
  // another thread by the ArrayBufferTracker.
  base::Mutex mutex_;

  size_t allocated_address_space_{0};

  // Track Wasm memory allocation information. This is keyed by the start of the
  // buffer, rather than by the start of the allocation.
  std::unordered_map<const void*, AllocationData> allocations_;

  // Empty backing stores still need to be backed by mapped pages when using
  // trap handlers. Because this could eat up address space quickly, we keep a
  // shared backing store here.
  AllocationData empty_backing_store_;

  // Keep pointers to
  Histogram* allocation_result_;
  Histogram* address_space_usage_mb_;  // in MiB

  DISALLOW_COPY_AND_ASSIGN(WasmMemoryTracker);
};

MaybeHandle<JSArrayBuffer> NewArrayBuffer(
    Isolate*, size_t size, SharedFlag shared = SharedFlag::kNotShared);

Handle<JSArrayBuffer> SetupArrayBuffer(
    Isolate*, void* backing_store, size_t size, bool is_external,
    SharedFlag shared = SharedFlag::kNotShared);

void DetachMemoryBuffer(Isolate* isolate, Handle<JSArrayBuffer> buffer,
                        bool free_memory);

}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // V8_WASM_WASM_MEMORY_H_