blob: a02797e94f61e8c71428633a4585a625dc5aadbd [file] [log] [blame]
[email protected]a22998a2013-11-10 05:00:501// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Bill Budge07c6ea62017-12-22 19:16:115#include "gin/array_buffer.h"
6
avi90e658dd2015-12-21 07:16:197#include <stddef.h>
[email protected]a22998a2013-11-10 05:00:508#include <stdlib.h>
9
Eric Holkb2fa95d2017-07-17 18:51:3610#include "base/allocator/partition_allocator/page_allocator.h"
[email protected]73dcce92014-02-20 08:24:0411#include "base/logging.h"
Alexei Filippov2eea1192018-03-01 18:01:0312#include "base/partition_alloc_buildflags.h"
Eric Holkb2fa95d2017-07-17 18:51:3613#include "build/build_config.h"
[email protected]73dcce92014-02-20 08:24:0414#include "gin/per_isolate_data.h"
15
Eric Holkb2fa95d2017-07-17 18:51:3616#if defined(OS_POSIX)
17#include <sys/mman.h>
18
19#ifndef MAP_ANONYMOUS
20#define MAP_ANONYMOUS MAP_ANON
21#endif
Bill Budge07c6ea62017-12-22 19:16:1122#endif // defined(OS_POSIX)
Eric Holkb2fa95d2017-07-17 18:51:3623
[email protected]a22998a2013-11-10 05:00:5024namespace gin {
25
[email protected]73dcce92014-02-20 08:24:0426namespace {
27
28gin::WrapperInfo g_array_buffer_wrapper_info = {gin::kEmbedderNativeGin};
29
30} // namespace
31
anujk.sharmac1b6156b2015-01-20 21:47:3632static_assert(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2,
33 "array buffers must have two internal fields");
[email protected]a22998a2013-11-10 05:00:5034
[email protected]a22998a2013-11-10 05:00:5035// ArrayBufferAllocator -------------------------------------------------------
36
37void* ArrayBufferAllocator::Allocate(size_t length) {
Bill Budge07c6ea62017-12-22 19:16:1138 // TODO(bbudge) Use partition allocator for malloc/calloc allocations.
[email protected]a22998a2013-11-10 05:00:5039 return calloc(1, length);
40}
41
42void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
43 return malloc(length);
44}
45
46void ArrayBufferAllocator::Free(void* data, size_t length) {
47 free(data);
48}
49
50ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() {
51 static ArrayBufferAllocator* instance = new ArrayBufferAllocator();
52 return instance;
53}
54
[email protected]e87f3122013-11-12 00:41:2755// ArrayBuffer::Private -------------------------------------------------------
[email protected]a22998a2013-11-10 05:00:5056
57// This class exists to solve a tricky lifetime problem. The V8 API doesn't
58// want to expose a direct view into the memory behind an array buffer because
59// V8 might deallocate that memory during garbage collection. Instead, the V8
60// API forces us to externalize the buffer and take ownership of the memory.
61// In order to know when to free the memory, we need to figure out both when
62// we're done with it and when V8 is done with it.
63//
64// To determine whether we're done with the memory, every view we have into
[email protected]e87f3122013-11-12 00:41:2765// the array buffer takes a reference to the ArrayBuffer::Private object that
[email protected]a22998a2013-11-10 05:00:5066// actually owns the memory. To determine when V8 is done with the memory, we
67// open a weak handle to the ArrayBuffer object. When we receive the weak
68// callback, we know the object is about to be garbage collected and we can
69// drop V8's implied reference to the memory.
70//
[email protected]e87f3122013-11-12 00:41:2771// The final subtlety is that we need every ArrayBuffer into the same array
72// buffer to AddRef the same ArrayBuffer::Private. To make that work, we store
73// a pointer to the ArrayBuffer::Private object in an internal field of the
[email protected]a22998a2013-11-10 05:00:5074// ArrayBuffer object.
75//
[email protected]855ab432013-11-18 17:09:3676class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> {
[email protected]a22998a2013-11-10 05:00:5077 public:
78 static scoped_refptr<Private> From(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:4879 v8::Local<v8::ArrayBuffer> array);
[email protected]a22998a2013-11-10 05:00:5080
[email protected]a22998a2013-11-10 05:00:5081 void* buffer() const { return buffer_; }
82 size_t length() const { return length_; }
83
84 private:
[email protected]855ab432013-11-18 17:09:3685 friend class base::RefCounted<Private>;
Stephan Herhut3c2d95272018-09-24 18:51:5486 using DataDeleter = void (*)(void* data, size_t length, void* info);
[email protected]855ab432013-11-18 17:09:3687
deepak.sfaaa1b62015-04-30 07:30:4888 Private(v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array);
[email protected]a22998a2013-11-10 05:00:5089 ~Private();
90
dcarney99ade9082015-04-22 09:55:4291 static void FirstWeakCallback(const v8::WeakCallbackInfo<Private>& data);
92 static void SecondWeakCallback(const v8::WeakCallbackInfo<Private>& data);
[email protected]a22998a2013-11-10 05:00:5093
dcarney99ade9082015-04-22 09:55:4294 v8::Global<v8::ArrayBuffer> array_buffer_;
[email protected]855ab432013-11-18 17:09:3695 scoped_refptr<Private> self_reference_;
[email protected]73dcce92014-02-20 08:24:0496 v8::Isolate* isolate_;
[email protected]a22998a2013-11-10 05:00:5097 void* buffer_;
98 size_t length_;
Stephan Herhut3c2d95272018-09-24 18:51:5499 DataDeleter deleter_;
100 void* deleter_data_;
[email protected]a22998a2013-11-10 05:00:50101};
102
[email protected]e87f3122013-11-12 00:41:27103scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From(
deepak.sfaaa1b62015-04-30 07:30:48104 v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array) {
[email protected]a22998a2013-11-10 05:00:50105 if (array->IsExternal()) {
deepak.sfaaa1b62015-04-30 07:30:48106 CHECK_EQ(WrapperInfo::From(v8::Local<v8::Object>::Cast(array)),
[email protected]73dcce92014-02-20 08:24:04107 &g_array_buffer_wrapper_info)
108 << "Cannot mix blink and gin ArrayBuffers";
kylecharda69d882017-10-04 05:49:52109 return base::WrapRefCounted(static_cast<Private*>(
[email protected]73dcce92014-02-20 08:24:04110 array->GetAlignedPointerFromInternalField(kEncodedValueIndex)));
[email protected]a22998a2013-11-10 05:00:50111 }
kylecharda69d882017-10-04 05:49:52112 return base::WrapRefCounted(new Private(isolate, array));
[email protected]a22998a2013-11-10 05:00:50113}
114
[email protected]e87f3122013-11-12 00:41:27115ArrayBuffer::Private::Private(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48116 v8::Local<v8::ArrayBuffer> array)
[email protected]73dcce92014-02-20 08:24:04117 : array_buffer_(isolate, array), isolate_(isolate) {
[email protected]a22998a2013-11-10 05:00:50118 // Take ownership of the array buffer.
[email protected]73dcce92014-02-20 08:24:04119 CHECK(!array->IsExternal());
[email protected]a22998a2013-11-10 05:00:50120 v8::ArrayBuffer::Contents contents = array->Externalize();
121 buffer_ = contents.Data();
122 length_ = contents.ByteLength();
Stephan Herhut3c2d95272018-09-24 18:51:54123 deleter_ = contents.Deleter();
124 deleter_data_ = contents.DeleterData();
[email protected]a22998a2013-11-10 05:00:50125
[email protected]73dcce92014-02-20 08:24:04126 array->SetAlignedPointerInInternalField(kWrapperInfoIndex,
127 &g_array_buffer_wrapper_info);
128 array->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
[email protected]a22998a2013-11-10 05:00:50129
dcarney99ade9082015-04-22 09:55:42130 self_reference_ = this; // Cleared in SecondWeakCallback.
131 array_buffer_.SetWeak(this, FirstWeakCallback,
132 v8::WeakCallbackType::kParameter);
[email protected]a22998a2013-11-10 05:00:50133}
134
[email protected]e87f3122013-11-12 00:41:27135ArrayBuffer::Private::~Private() {
Stephan Herhut3c2d95272018-09-24 18:51:54136 deleter_(buffer_, length_, deleter_data_);
[email protected]a22998a2013-11-10 05:00:50137}
138
dcarney99ade9082015-04-22 09:55:42139void ArrayBuffer::Private::FirstWeakCallback(
140 const v8::WeakCallbackInfo<Private>& data) {
[email protected]a22998a2013-11-10 05:00:50141 Private* parameter = data.GetParameter();
142 parameter->array_buffer_.Reset();
dcarney99ade9082015-04-22 09:55:42143 data.SetSecondPassCallback(SecondWeakCallback);
144}
145
146void ArrayBuffer::Private::SecondWeakCallback(
147 const v8::WeakCallbackInfo<Private>& data) {
148 Private* parameter = data.GetParameter();
[email protected]93f9f3602013-11-21 18:38:51149 parameter->self_reference_ = NULL;
[email protected]a22998a2013-11-10 05:00:50150}
151
[email protected]e87f3122013-11-12 00:41:27152// ArrayBuffer ----------------------------------------------------------------
[email protected]a22998a2013-11-10 05:00:50153
[email protected]7618ebbb2013-11-27 03:38:26154ArrayBuffer::ArrayBuffer()
155 : bytes_(0),
[email protected]e87f3122013-11-12 00:41:27156 num_bytes_(0) {
[email protected]a22998a2013-11-10 05:00:50157}
158
[email protected]e87f3122013-11-12 00:41:27159ArrayBuffer::ArrayBuffer(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48160 v8::Local<v8::ArrayBuffer> array) {
[email protected]7618ebbb2013-11-27 03:38:26161 private_ = ArrayBuffer::Private::From(isolate, array);
[email protected]a22998a2013-11-10 05:00:50162 bytes_ = private_->buffer();
163 num_bytes_ = private_->length();
164}
165
Chris Watkins756035a2017-12-01 03:03:27166ArrayBuffer::~ArrayBuffer() = default;
[email protected]e87f3122013-11-12 00:41:27167
Chris Watkins756035a2017-12-01 03:03:27168ArrayBuffer& ArrayBuffer::operator=(const ArrayBuffer& other) = default;
[email protected]48c21632013-12-12 21:32:34169
[email protected]e87f3122013-11-12 00:41:27170// Converter<ArrayBuffer> -----------------------------------------------------
171
[email protected]7618ebbb2013-11-27 03:38:26172bool Converter<ArrayBuffer>::FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48173 v8::Local<v8::Value> val,
[email protected]e87f3122013-11-12 00:41:27174 ArrayBuffer* out) {
175 if (!val->IsArrayBuffer())
176 return false;
deepak.sfaaa1b62015-04-30 07:30:48177 *out = ArrayBuffer(isolate, v8::Local<v8::ArrayBuffer>::Cast(val));
[email protected]e87f3122013-11-12 00:41:27178 return true;
179}
180
181// ArrayBufferView ------------------------------------------------------------
182
[email protected]7618ebbb2013-11-27 03:38:26183ArrayBufferView::ArrayBufferView()
184 : offset_(0),
[email protected]e87f3122013-11-12 00:41:27185 num_bytes_(0) {
186}
187
188ArrayBufferView::ArrayBufferView(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48189 v8::Local<v8::ArrayBufferView> view)
[email protected]e87f3122013-11-12 00:41:27190 : array_buffer_(isolate, view->Buffer()),
191 offset_(view->ByteOffset()),
192 num_bytes_(view->ByteLength()) {
193}
194
Chris Watkins756035a2017-12-01 03:03:27195ArrayBufferView::~ArrayBufferView() = default;
[email protected]e87f3122013-11-12 00:41:27196
Chris Watkins756035a2017-12-01 03:03:27197ArrayBufferView& ArrayBufferView::operator=(const ArrayBufferView& other) =
198 default;
[email protected]dfc613d2014-05-16 13:16:52199
[email protected]e87f3122013-11-12 00:41:27200// Converter<ArrayBufferView> -------------------------------------------------
201
[email protected]7618ebbb2013-11-27 03:38:26202bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48203 v8::Local<v8::Value> val,
[email protected]e87f3122013-11-12 00:41:27204 ArrayBufferView* out) {
205 if (!val->IsArrayBufferView())
206 return false;
deepak.sfaaa1b62015-04-30 07:30:48207 *out = ArrayBufferView(isolate, v8::Local<v8::ArrayBufferView>::Cast(val));
[email protected]e87f3122013-11-12 00:41:27208 return true;
209}
210
[email protected]a22998a2013-11-10 05:00:50211} // namespace gin