blob: f84934bfd712dbad0e85d908165a5a4033bff170 [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>;
86
deepak.sfaaa1b62015-04-30 07:30:4887 Private(v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array);
[email protected]a22998a2013-11-10 05:00:5088 ~Private();
89
dcarney99ade9082015-04-22 09:55:4290 static void FirstWeakCallback(const v8::WeakCallbackInfo<Private>& data);
91 static void SecondWeakCallback(const v8::WeakCallbackInfo<Private>& data);
[email protected]a22998a2013-11-10 05:00:5092
dcarney99ade9082015-04-22 09:55:4293 v8::Global<v8::ArrayBuffer> array_buffer_;
[email protected]855ab432013-11-18 17:09:3694 scoped_refptr<Private> self_reference_;
[email protected]73dcce92014-02-20 08:24:0495 v8::Isolate* isolate_;
[email protected]a22998a2013-11-10 05:00:5096 void* buffer_;
97 size_t length_;
Eric Holkb2fa95d2017-07-17 18:51:3698 void* allocation_base_;
99 size_t allocation_length_;
100 v8::ArrayBuffer::Allocator::AllocationMode allocation_mode_;
[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();
Bill Budge2ca35142018-02-21 23:22:22121 // We shouldn't receive large page-allocated array buffers.
122 CHECK_NE(v8::ArrayBuffer::Allocator::AllocationMode::kReservation,
123 contents.AllocationMode());
[email protected]a22998a2013-11-10 05:00:50124 buffer_ = contents.Data();
125 length_ = contents.ByteLength();
Eric Holkb2fa95d2017-07-17 18:51:36126 allocation_base_ = contents.AllocationBase();
127 allocation_length_ = contents.AllocationLength();
Eric Holkb2fa95d2017-07-17 18:51:36128
129 DCHECK(reinterpret_cast<uintptr_t>(allocation_base_) <=
130 reinterpret_cast<uintptr_t>(buffer_));
131 DCHECK(reinterpret_cast<uintptr_t>(buffer_) + length_ <=
132 reinterpret_cast<uintptr_t>(allocation_base_) + allocation_length_);
[email protected]a22998a2013-11-10 05:00:50133
[email protected]73dcce92014-02-20 08:24:04134 array->SetAlignedPointerInInternalField(kWrapperInfoIndex,
135 &g_array_buffer_wrapper_info);
136 array->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
[email protected]a22998a2013-11-10 05:00:50137
dcarney99ade9082015-04-22 09:55:42138 self_reference_ = this; // Cleared in SecondWeakCallback.
139 array_buffer_.SetWeak(this, FirstWeakCallback,
140 v8::WeakCallbackType::kParameter);
[email protected]a22998a2013-11-10 05:00:50141}
142
[email protected]e87f3122013-11-12 00:41:27143ArrayBuffer::Private::~Private() {
Bill Budge2ca35142018-02-21 23:22:22144 PerIsolateData::From(isolate_)->allocator()->Free(allocation_base_,
145 allocation_length_);
[email protected]a22998a2013-11-10 05:00:50146}
147
dcarney99ade9082015-04-22 09:55:42148void ArrayBuffer::Private::FirstWeakCallback(
149 const v8::WeakCallbackInfo<Private>& data) {
[email protected]a22998a2013-11-10 05:00:50150 Private* parameter = data.GetParameter();
151 parameter->array_buffer_.Reset();
dcarney99ade9082015-04-22 09:55:42152 data.SetSecondPassCallback(SecondWeakCallback);
153}
154
155void ArrayBuffer::Private::SecondWeakCallback(
156 const v8::WeakCallbackInfo<Private>& data) {
157 Private* parameter = data.GetParameter();
[email protected]93f9f3602013-11-21 18:38:51158 parameter->self_reference_ = NULL;
[email protected]a22998a2013-11-10 05:00:50159}
160
[email protected]e87f3122013-11-12 00:41:27161// ArrayBuffer ----------------------------------------------------------------
[email protected]a22998a2013-11-10 05:00:50162
[email protected]7618ebbb2013-11-27 03:38:26163ArrayBuffer::ArrayBuffer()
164 : bytes_(0),
[email protected]e87f3122013-11-12 00:41:27165 num_bytes_(0) {
[email protected]a22998a2013-11-10 05:00:50166}
167
[email protected]e87f3122013-11-12 00:41:27168ArrayBuffer::ArrayBuffer(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48169 v8::Local<v8::ArrayBuffer> array) {
[email protected]7618ebbb2013-11-27 03:38:26170 private_ = ArrayBuffer::Private::From(isolate, array);
[email protected]a22998a2013-11-10 05:00:50171 bytes_ = private_->buffer();
172 num_bytes_ = private_->length();
173}
174
Chris Watkins756035a2017-12-01 03:03:27175ArrayBuffer::~ArrayBuffer() = default;
[email protected]e87f3122013-11-12 00:41:27176
Chris Watkins756035a2017-12-01 03:03:27177ArrayBuffer& ArrayBuffer::operator=(const ArrayBuffer& other) = default;
[email protected]48c21632013-12-12 21:32:34178
[email protected]e87f3122013-11-12 00:41:27179// Converter<ArrayBuffer> -----------------------------------------------------
180
[email protected]7618ebbb2013-11-27 03:38:26181bool Converter<ArrayBuffer>::FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48182 v8::Local<v8::Value> val,
[email protected]e87f3122013-11-12 00:41:27183 ArrayBuffer* out) {
184 if (!val->IsArrayBuffer())
185 return false;
deepak.sfaaa1b62015-04-30 07:30:48186 *out = ArrayBuffer(isolate, v8::Local<v8::ArrayBuffer>::Cast(val));
[email protected]e87f3122013-11-12 00:41:27187 return true;
188}
189
190// ArrayBufferView ------------------------------------------------------------
191
[email protected]7618ebbb2013-11-27 03:38:26192ArrayBufferView::ArrayBufferView()
193 : offset_(0),
[email protected]e87f3122013-11-12 00:41:27194 num_bytes_(0) {
195}
196
197ArrayBufferView::ArrayBufferView(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48198 v8::Local<v8::ArrayBufferView> view)
[email protected]e87f3122013-11-12 00:41:27199 : array_buffer_(isolate, view->Buffer()),
200 offset_(view->ByteOffset()),
201 num_bytes_(view->ByteLength()) {
202}
203
Chris Watkins756035a2017-12-01 03:03:27204ArrayBufferView::~ArrayBufferView() = default;
[email protected]e87f3122013-11-12 00:41:27205
Chris Watkins756035a2017-12-01 03:03:27206ArrayBufferView& ArrayBufferView::operator=(const ArrayBufferView& other) =
207 default;
[email protected]dfc613d2014-05-16 13:16:52208
[email protected]e87f3122013-11-12 00:41:27209// Converter<ArrayBufferView> -------------------------------------------------
210
[email protected]7618ebbb2013-11-27 03:38:26211bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate,
deepak.sfaaa1b62015-04-30 07:30:48212 v8::Local<v8::Value> val,
[email protected]e87f3122013-11-12 00:41:27213 ArrayBufferView* out) {
214 if (!val->IsArrayBufferView())
215 return false;
deepak.sfaaa1b62015-04-30 07:30:48216 *out = ArrayBufferView(isolate, v8::Local<v8::ArrayBufferView>::Cast(val));
[email protected]e87f3122013-11-12 00:41:27217 return true;
218}
219
[email protected]a22998a2013-11-10 05:00:50220} // namespace gin