1 // 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 5 #include "gin/array_buffer.h" 6 7 #include <stdlib.h> 8 9 namespace gin { 10 11 COMPILE_ASSERT(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2, 12 array_buffers_must_have_two_internal_fields); 13 14 static const int kBufferViewPrivateIndex = 0; 15 16 // ArrayBufferAllocator ------------------------------------------------------- 17 18 void* ArrayBufferAllocator::Allocate(size_t length) { 19 return calloc(1, length); 20 } 21 22 void* ArrayBufferAllocator::AllocateUninitialized(size_t length) { 23 return malloc(length); 24 } 25 26 void ArrayBufferAllocator::Free(void* data, size_t length) { 27 free(data); 28 } 29 30 ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() { 31 static ArrayBufferAllocator* instance = new ArrayBufferAllocator(); 32 return instance; 33 } 34 35 // ArrayBuffer::Private ------------------------------------------------------- 36 37 // This class exists to solve a tricky lifetime problem. The V8 API doesn't 38 // want to expose a direct view into the memory behind an array buffer because 39 // V8 might deallocate that memory during garbage collection. Instead, the V8 40 // API forces us to externalize the buffer and take ownership of the memory. 41 // In order to know when to free the memory, we need to figure out both when 42 // we're done with it and when V8 is done with it. 43 // 44 // To determine whether we're done with the memory, every view we have into 45 // the array buffer takes a reference to the ArrayBuffer::Private object that 46 // actually owns the memory. To determine when V8 is done with the memory, we 47 // open a weak handle to the ArrayBuffer object. When we receive the weak 48 // callback, we know the object is about to be garbage collected and we can 49 // drop V8's implied reference to the memory. 50 // 51 // The final subtlety is that we need every ArrayBuffer into the same array 52 // buffer to AddRef the same ArrayBuffer::Private. To make that work, we store 53 // a pointer to the ArrayBuffer::Private object in an internal field of the 54 // ArrayBuffer object. 55 // 56 class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> { 57 public: 58 static scoped_refptr<Private> From(v8::Isolate* isolate, 59 v8::Handle<v8::ArrayBuffer> array); 60 61 void* buffer() const { return buffer_; } 62 size_t length() const { return length_; } 63 64 private: 65 friend class base::RefCounted<Private>; 66 67 Private(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array); 68 ~Private(); 69 70 static void WeakCallback( 71 const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data); 72 73 v8::Persistent<v8::ArrayBuffer> array_buffer_; 74 scoped_refptr<Private> self_reference_; 75 void* buffer_; 76 size_t length_; 77 }; 78 79 scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From( 80 v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) { 81 if (array->IsExternal()) { 82 return make_scoped_refptr(static_cast<Private*>( 83 array->GetAlignedPointerFromInternalField(kBufferViewPrivateIndex))); 84 } 85 return make_scoped_refptr(new Private(isolate, array)); 86 } 87 88 ArrayBuffer::Private::Private(v8::Isolate* isolate, 89 v8::Handle<v8::ArrayBuffer> array) 90 : array_buffer_(isolate, array) { 91 // Take ownership of the array buffer. 92 v8::ArrayBuffer::Contents contents = array->Externalize(); 93 buffer_ = contents.Data(); 94 length_ = contents.ByteLength(); 95 96 array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this); 97 98 self_reference_ = this; // Cleared in WeakCallback. 99 array_buffer_.SetWeak(this, WeakCallback); 100 } 101 102 ArrayBuffer::Private::~Private() { 103 ArrayBufferAllocator::SharedInstance()->Free(buffer_, length_); 104 } 105 106 void ArrayBuffer::Private::WeakCallback( 107 const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data) { 108 Private* parameter = data.GetParameter(); 109 parameter->array_buffer_.Reset(); 110 parameter->self_reference_ = NULL; 111 } 112 113 // ArrayBuffer ---------------------------------------------------------------- 114 115 ArrayBuffer::ArrayBuffer() 116 : bytes_(0), 117 num_bytes_(0) { 118 } 119 120 ArrayBuffer::ArrayBuffer(v8::Isolate* isolate, 121 v8::Handle<v8::ArrayBuffer> array) { 122 private_ = ArrayBuffer::Private::From(isolate, array); 123 bytes_ = private_->buffer(); 124 num_bytes_ = private_->length(); 125 } 126 127 ArrayBuffer::~ArrayBuffer() { 128 } 129 130 ArrayBuffer& ArrayBuffer::operator=(const ArrayBuffer& other) { 131 private_ = other.private_; 132 bytes_ = other.bytes_; 133 num_bytes_ = other.num_bytes_; 134 return *this; 135 } 136 137 // Converter<ArrayBuffer> ----------------------------------------------------- 138 139 bool Converter<ArrayBuffer>::FromV8(v8::Isolate* isolate, 140 v8::Handle<v8::Value> val, 141 ArrayBuffer* out) { 142 if (!val->IsArrayBuffer()) 143 return false; 144 *out = ArrayBuffer(isolate, v8::Handle<v8::ArrayBuffer>::Cast(val)); 145 return true; 146 } 147 148 // ArrayBufferView ------------------------------------------------------------ 149 150 ArrayBufferView::ArrayBufferView() 151 : offset_(0), 152 num_bytes_(0) { 153 } 154 155 ArrayBufferView::ArrayBufferView(v8::Isolate* isolate, 156 v8::Handle<v8::ArrayBufferView> view) 157 : array_buffer_(isolate, view->Buffer()), 158 offset_(view->ByteOffset()), 159 num_bytes_(view->ByteLength()) { 160 } 161 162 ArrayBufferView::~ArrayBufferView() { 163 } 164 165 // Converter<ArrayBufferView> ------------------------------------------------- 166 167 bool Converter<ArrayBufferView>::FromV8(v8::Isolate* isolate, 168 v8::Handle<v8::Value> val, 169 ArrayBufferView* out) { 170 if (!val->IsArrayBufferView()) 171 return false; 172 *out = ArrayBufferView(isolate, v8::Handle<v8::ArrayBufferView>::Cast(val)); 173 return true; 174 } 175 176 } // namespace gin 177