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