| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 // BufferView::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 BufferView::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 BufferView into the same array | 
|  | 52 // buffer to AddRef the same BufferView::Private. To make that work, we store a | 
|  | 53 // pointer to the BufferView::Private object in an internal field of the | 
|  | 54 // ArrayBuffer object. | 
|  | 55 // | 
|  | 56 class BufferView::Private { | 
|  | 57  public: | 
|  | 58   static scoped_refptr<Private> From(v8::Isolate* isolate, | 
|  | 59                                      v8::Handle<v8::ArrayBuffer> array); | 
|  | 60 | 
|  | 61   void AddRef(); | 
|  | 62   void Release(); | 
|  | 63 | 
|  | 64   void* buffer() const { return buffer_; } | 
|  | 65   size_t length() const { return length_; } | 
|  | 66 | 
|  | 67  private: | 
|  | 68   Private(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array); | 
|  | 69   ~Private(); | 
|  | 70 | 
|  | 71   static void WeakCallback( | 
|  | 72       const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data); | 
|  | 73 | 
|  | 74   size_t ref_count_; | 
|  | 75   v8::Persistent<v8::ArrayBuffer> array_buffer_; | 
|  | 76   void* buffer_; | 
|  | 77   size_t length_; | 
|  | 78 }; | 
|  | 79 | 
|  | 80 scoped_refptr<BufferView::Private> BufferView::Private::From( | 
|  | 81     v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) { | 
|  | 82   if (array->IsExternal()) { | 
|  | 83     return make_scoped_refptr(static_cast<Private*>( | 
|  | 84         array->GetAlignedPointerFromInternalField(kBufferViewPrivateIndex))); | 
|  | 85   } | 
|  | 86   return make_scoped_refptr(new Private(isolate, array)); | 
|  | 87 } | 
|  | 88 | 
|  | 89 void BufferView::Private::AddRef() { | 
|  | 90   ++ref_count_; | 
|  | 91 } | 
|  | 92 | 
|  | 93 void BufferView::Private::Release() { | 
|  | 94   if (--ref_count_) | 
|  | 95     return; | 
|  | 96   delete this; | 
|  | 97 } | 
|  | 98 | 
|  | 99 BufferView::Private::Private(v8::Isolate* isolate, | 
|  | 100                              v8::Handle<v8::ArrayBuffer> array) | 
|  | 101     : ref_count_(0), | 
|  | 102       array_buffer_(isolate, array) { | 
|  | 103   // Take ownership of the array buffer. | 
|  | 104   v8::ArrayBuffer::Contents contents = array->Externalize(); | 
|  | 105   buffer_ = contents.Data(); | 
|  | 106   length_ = contents.ByteLength(); | 
|  | 107 | 
|  | 108   array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this); | 
|  | 109 | 
|  | 110   AddRef();  // Balanced in WeakCallback. | 
|  | 111   array_buffer_.SetWeak(this, WeakCallback); | 
|  | 112 } | 
|  | 113 | 
|  | 114 BufferView::Private::~Private() { | 
|  | 115   ArrayBufferAllocator::SharedInstance()->Free(buffer_, length_); | 
|  | 116 } | 
|  | 117 | 
|  | 118 void BufferView::Private::WeakCallback( | 
|  | 119     const v8::WeakCallbackData<v8::ArrayBuffer, Private>& data) { | 
|  | 120   Private* parameter = data.GetParameter(); | 
|  | 121   parameter->array_buffer_.Reset(); | 
|  | 122   parameter->Release();  // Balanced in BufferView::Private::Private. | 
|  | 123 } | 
|  | 124 | 
|  | 125 // BufferView ----------------------------------------------------------------- | 
|  | 126 | 
|  | 127 BufferView::BufferView(v8::Isolate* isolate, | 
|  | 128                        v8::Handle<v8::ArrayBufferView> view) { | 
|  | 129   Initialize(isolate, view->Buffer()); | 
|  | 130   uint8_t* ptr = static_cast<uint8_t*>(bytes_); | 
|  | 131   bytes_ = static_cast<void*>(ptr + view->ByteOffset()); | 
|  | 132   num_bytes_ = view->ByteLength(); | 
|  | 133 } | 
|  | 134 | 
|  | 135 BufferView::BufferView(v8::Isolate* isolate, | 
|  | 136                        v8::Handle<v8::ArrayBuffer> array) { | 
|  | 137   Initialize(isolate, array); | 
|  | 138 } | 
|  | 139 | 
|  | 140 BufferView::~BufferView() { | 
|  | 141 } | 
|  | 142 | 
|  | 143 void BufferView::Initialize(v8::Isolate* isolate, | 
|  | 144                             v8::Handle<v8::ArrayBuffer> array) { | 
|  | 145   private_ = BufferView::Private::From(isolate, array); | 
|  | 146   bytes_ = private_->buffer(); | 
|  | 147   num_bytes_ = private_->length(); | 
|  | 148 } | 
|  | 149 | 
|  | 150 }  // namespace gin | 
| OLD | NEW | 
|---|