[M120 Migration] Set IO|GPU thread type with higher priorites
[platform/framework/web/chromium-efl.git] / gin / array_buffer.cc
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "gin/array_buffer.h"
6
7 #include <stddef.h>
8 #include <stdlib.h>
9
10 #include "base/allocator/partition_allocator/src/partition_alloc/page_allocator.h"
11 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc.h"
12 #include "base/allocator/partition_allocator/src/partition_alloc/partition_root.h"
13 #include "base/bits.h"
14 #include "base/check_op.h"
15 #include "base/no_destructor.h"
16 #include "build/build_config.h"
17 #include "gin/per_isolate_data.h"
18 #include "v8/include/v8-initialization.h"
19
20 #if BUILDFLAG(IS_POSIX)
21 #include <sys/mman.h>
22
23 #ifndef MAP_ANONYMOUS
24 #define MAP_ANONYMOUS MAP_ANON
25 #endif
26 #endif  // BUILDFLAG(IS_POSIX)
27
28 namespace gin {
29
30 static_assert(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2,
31               "array buffers must have two internal fields");
32
33 // ArrayBufferAllocator -------------------------------------------------------
34 partition_alloc::PartitionRoot* ArrayBufferAllocator::partition_ = nullptr;
35
36 void* ArrayBufferAllocator::Allocate(size_t length) {
37   constexpr partition_alloc::AllocFlags flags =
38       partition_alloc::AllocFlags::kZeroFill |
39       partition_alloc::AllocFlags::kReturnNull;
40   return AllocateInternal<flags>(length);
41 }
42
43 void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
44   constexpr partition_alloc::AllocFlags flags =
45       partition_alloc::AllocFlags::kReturnNull;
46   return AllocateInternal<flags>(length);
47 }
48
49 template <partition_alloc::AllocFlags flags>
50 void* ArrayBufferAllocator::AllocateInternal(size_t length) {
51 #ifdef V8_ENABLE_SANDBOX
52   // The V8 sandbox requires all ArrayBuffer backing stores to be allocated
53   // inside the sandbox address space. This isn't guaranteed if allocation
54   // override hooks (which are e.g. used by GWP-ASan) are enabled or if a
55   // memory tool (e.g. ASan) overrides malloc, so disable both.
56   constexpr auto new_flags = flags |
57                              partition_alloc::AllocFlags::kNoOverrideHooks |
58                              partition_alloc::AllocFlags::kNoMemoryToolOverride;
59 #else
60   constexpr auto new_flags = flags;
61 #endif
62   return partition_->AllocInline<new_flags>(length,
63                                             "gin::ArrayBufferAllocator");
64 }
65
66 void ArrayBufferAllocator::Free(void* data, size_t length) {
67 #ifdef V8_ENABLE_SANDBOX
68   // See |AllocateMemoryWithFlags|.
69   partition_->Free<partition_alloc::FreeFlags::kNoMemoryToolOverride>(data);
70 #else
71   partition_->Free(data);
72 #endif
73 }
74
75 // static
76 ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() {
77   static ArrayBufferAllocator* instance = new ArrayBufferAllocator();
78   return instance;
79 }
80
81 // static
82 void ArrayBufferAllocator::InitializePartition() {
83   static base::NoDestructor<partition_alloc::PartitionAllocator>
84       partition_allocator(partition_alloc::PartitionOptions{
85           .star_scan_quarantine = partition_alloc::PartitionOptions::kAllowed,
86           .backup_ref_ptr = partition_alloc::PartitionOptions::kDisabled,
87           .use_configurable_pool = partition_alloc::PartitionOptions::kAllowed,
88       });
89
90   partition_ = partition_allocator->root();
91 }
92
93 // ArrayBuffer ----------------------------------------------------------------
94 ArrayBuffer::ArrayBuffer() = default;
95
96 ArrayBuffer::ArrayBuffer(v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array)
97     : backing_store_(array->GetBackingStore()) {}
98
99 ArrayBuffer::~ArrayBuffer() = default;
100
101 ArrayBuffer& ArrayBuffer::operator=(const ArrayBuffer& other) = default;
102
103 // Converter<ArrayBuffer> -----------------------------------------------------
104
105 bool Converter<ArrayBuffer>::FromV8(v8::Isolate* isolate,
106                                     v8::Local<v8::Value> val,
107                                     ArrayBuffer* out) {
108   if (!val->IsArrayBuffer())
109     return false;
110   *out = ArrayBuffer(isolate, v8::Local<v8::ArrayBuffer>::Cast(val));
111   return true;
112 }
113
114 // ArrayBufferView ------------------------------------------------------------
115
116 ArrayBufferView::ArrayBufferView()
117     : offset_(0),
118       num_bytes_(0) {
119 }
120
121 ArrayBufferView::ArrayBufferView(v8::Isolate* isolate,
122                                  v8::Local<v8::ArrayBufferView> view)
123     : array_buffer_(isolate, view->Buffer()),
124       offset_(view->ByteOffset()),
125       num_bytes_(view->ByteLength()) {
126 }
127
128 ArrayBufferView::~ArrayBufferView() = default;
129
130 ArrayBufferView& ArrayBufferView::operator=(const ArrayBufferView& other) =
131     default;
132
133 // Converter<ArrayBufferView> -------------------------------------------------
134
135 bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate,
136                                         v8::Local<v8::Value> val,
137                                         ArrayBufferView* out) {
138   if (!val->IsArrayBufferView())
139     return false;
140   *out = ArrayBufferView(isolate, v8::Local<v8::ArrayBufferView>::Cast(val));
141   return true;
142 }
143
144 // ArrayBufferSharedMemoryMapper ---------------------------------------------
145
146 namespace {
147 #ifdef V8_ENABLE_SANDBOX
148 // When the V8 sandbox is enabled, shared memory backing ArrayBuffers must be
149 // mapped into the sandbox address space. This custom SharedMemoryMapper
150 // implements this.
151
152 class ArrayBufferSharedMemoryMapper : public base::SharedMemoryMapper {
153  public:
154   absl::optional<base::span<uint8_t>> Map(
155       base::subtle::PlatformSharedMemoryHandle handle,
156       bool write_allowed,
157       uint64_t offset,
158       size_t size) override {
159     v8::VirtualAddressSpace* address_space = v8::V8::GetSandboxAddressSpace();
160     size_t allocation_granularity = address_space->allocation_granularity();
161
162     v8::PlatformSharedMemoryHandle v8_handle;
163 #if BUILDFLAG(IS_APPLE)
164     v8_handle = v8::SharedMemoryHandleFromMachMemoryEntry(handle);
165 #elif BUILDFLAG(IS_FUCHSIA)
166     v8_handle = v8::SharedMemoryHandleFromVMO(handle->get());
167 #elif BUILDFLAG(IS_WIN)
168     v8_handle = v8::SharedMemoryHandleFromFileMapping(handle);
169 #elif BUILDFLAG(IS_ANDROID)
170     v8_handle = v8::SharedMemoryHandleFromFileDescriptor(handle);
171 #elif BUILDFLAG(IS_POSIX)
172     v8_handle = v8::SharedMemoryHandleFromFileDescriptor(handle.fd);
173 #else
174 #error "Unknown platform"
175 #endif
176
177     // Size and offset must be a multiple of the page allocation granularity.
178     // The caller already ensures that the offset is a multiple of the
179     // allocation granularity though.
180     CHECK_EQ(0UL, offset % allocation_granularity);
181     size_t mapping_size = base::bits::AlignUp(size, allocation_granularity);
182
183     v8::PagePermissions permissions = write_allowed
184                                           ? v8::PagePermissions::kReadWrite
185                                           : v8::PagePermissions::kRead;
186     uintptr_t mapping = v8::V8::GetSandboxAddressSpace()->AllocateSharedPages(
187         0, mapping_size, permissions, v8_handle, offset);
188     if (!mapping)
189       return absl::nullopt;
190
191     return base::make_span(reinterpret_cast<uint8_t*>(mapping), size);
192   }
193
194   void Unmap(base::span<uint8_t> mapping) override {
195     v8::VirtualAddressSpace* address_space = v8::V8::GetSandboxAddressSpace();
196     size_t allocation_granularity = address_space->allocation_granularity();
197
198     uintptr_t address = reinterpret_cast<uintptr_t>(mapping.data());
199     CHECK_EQ(0UL, address % allocation_granularity);
200     size_t mapping_size =
201         base::bits::AlignUp(mapping.size(), allocation_granularity);
202
203     address_space->FreeSharedPages(address, mapping_size);
204   }
205 };
206 #endif  // V8_ENABLE_SANDBOX
207 }  // namespace
208
209 base::SharedMemoryMapper* GetSharedMemoryMapperForArrayBuffers() {
210 #if V8_ENABLE_SANDBOX
211   static ArrayBufferSharedMemoryMapper instance;
212   return &instance;
213 #else
214   return base::SharedMemoryMapper::GetDefaultInstance();
215 #endif
216 }
217
218 }  // namespace gin