Shaka Player Embedded
byte_buffer.cc
Go to the documentation of this file.
1 // Copyright 2016 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
16 
17 #include <utility>
18 
19 #include "src/memory/heap_tracer.h"
20 
21 namespace shaka {
22 
23 namespace {
24 #ifdef USING_V8
25 uint8_t* GetDataPointer(v8::Local<v8::ArrayBuffer> buffer) {
26  return reinterpret_cast<uint8_t*>(buffer->GetContents().Data());
27 }
28 #elif defined(USING_JSC)
29 void FreeData(void* data, void*) {
30  std::free(data); // NOLINT
31 }
32 #endif
33 } // namespace
34 
36 
37 ByteBuffer::ByteBuffer(const uint8_t* data, size_t data_size) {
38  SetFromBuffer(data, data_size);
39 }
40 
42  : buffer_(std::move(other.buffer_)),
43  ptr_(other.ptr_),
44  size_(other.size_),
45  own_ptr_(other.own_ptr_) {
46  other.ClearFields();
47 }
48 
50  Clear();
51 }
52 
54  Clear();
55 
56  buffer_ = std::move(other.buffer_);
57  ptr_ = other.ptr_;
58  size_ = other.size_;
59  own_ptr_ = other.own_ptr_;
60 
61  other.ClearFields();
62  return *this;
63 }
64 
65 
67  if (own_ptr_)
68  std::free(ptr_); // NOLINT
69  ClearFields();
70 }
71 
73  ClearAndAllocateBuffer(other.Size());
74  other.CopyDataTo(ptr_, size_);
75 }
76 
77 void ByteBuffer::SetFromBuffer(const void* buffer, size_t size) {
78  ClearAndAllocateBuffer(size);
79  std::memcpy(ptr_, buffer, size_);
80 }
81 
82 bool ByteBuffer::TryConvert(Handle<JsValue> value) {
83 #if defined(USING_V8)
84  if (value.IsEmpty())
85  return false;
86 
87  if (value->IsArrayBuffer()) {
88  v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
89  ptr_ = GetDataPointer(buffer);
90  size_ = buffer->ByteLength();
91  } else if (value->IsArrayBufferView()) {
92  v8::Local<v8::ArrayBufferView> view = value.As<v8::ArrayBufferView>();
93  ptr_ = GetDataPointer(view->Buffer()) + view->ByteOffset();
94  size_ = view->ByteLength();
95  } else {
96  return false;
97  }
98 
99  buffer_ = value.As<v8::Object>();
100 #elif defined(USING_JSC)
101  JSContextRef cx = GetContext();
102  auto type = JSValueGetTypedArrayType(cx, value, nullptr);
103  if (type == kJSTypedArrayTypeNone)
104  return false;
105 
106  LocalVar<JsObject> object = UnsafeJsCast<JsObject>(value);
107  if (type == kJSTypedArrayTypeArrayBuffer) {
108  ptr_ = reinterpret_cast<uint8_t*>(
109  JSObjectGetArrayBufferBytesPtr(cx, object, nullptr));
110  size_ = JSObjectGetArrayBufferByteLength(cx, object, nullptr);
111  } else {
112  ptr_ = reinterpret_cast<uint8_t*>(
113  JSObjectGetTypedArrayBytesPtr(cx, object, nullptr)) +
114  JSObjectGetTypedArrayByteOffset(cx, object, nullptr);
115  size_ = JSObjectGetTypedArrayByteLength(cx, object, nullptr);
116  }
117  buffer_ = object;
118 #endif
119  own_ptr_ = false;
120  return true;
121 }
122 
123 ReturnVal<JsValue> ByteBuffer::ToJsValue() const {
124  if (buffer_.empty()) {
125  DCHECK(own_ptr_ || (!ptr_ && size_ == 0));
126 #if defined(USING_V8)
127  buffer_ = v8::ArrayBuffer::New(GetIsolate(), ptr_, size_,
128  v8::ArrayBufferCreationMode::kInternalized);
129 #elif defined(USING_JSC)
130  buffer_ = Handle<JsObject>(JSObjectMakeArrayBufferWithBytesNoCopy(
131  GetContext(), ptr_, size_, &FreeData, nullptr, nullptr));
132 #endif
133  CHECK(!buffer_.empty());
134  own_ptr_ = false;
135  }
136  return buffer_.value();
137 }
138 
139 ReturnVal<JsValue> ByteBuffer::ToJsValue(proto::ValueType kind) const {
140  ToJsValue(); // Ensure the buffer is available.
141  DCHECK(!own_ptr_);
142  DCHECK(!buffer_.empty());
143 
144 #if defined(USING_V8)
145  LocalVar<JsObject> local_buffer = buffer_.handle();
146  LocalVar<v8::ArrayBuffer> array_buffer;
147  size_t start = 0;
148  if (local_buffer->IsArrayBuffer()) {
149  array_buffer = local_buffer.As<v8::ArrayBuffer>();
150  } else {
151  DCHECK(array_buffer->IsArrayBufferView());
152  LocalVar<v8::ArrayBufferView> view = local_buffer.As<v8::ArrayBufferView>();
153  array_buffer = view->Buffer();
154  start = view->ByteOffset();
155  }
156 
157  switch (kind) {
158  case proto::ArrayBuffer:
159  return array_buffer;
160  case proto::DataView:
161  return v8::DataView::New(array_buffer, start, size_);
162  case proto::Int8Array:
163  return v8::Int8Array::New(array_buffer, start, size_);
164  case proto::Uint8Array:
165  return v8::Uint8Array::New(array_buffer, start, size_);
167  return v8::Uint8ClampedArray::New(array_buffer, start, size_);
168  case proto::Int16Array:
169  return v8::Int16Array::New(array_buffer, start, size_ / 2);
170  case proto::Uint16Array:
171  return v8::Uint16Array::New(array_buffer, start, size_ / 2);
172  case proto::Int32Array:
173  return v8::Int32Array::New(array_buffer, start, size_ / 4);
174  case proto::Uint32Array:
175  return v8::Uint32Array::New(array_buffer, start, size_ / 4);
176  case proto::Float32Array:
177  return v8::Float32Array::New(array_buffer, start, size_ / 4);
178  case proto::Float64Array:
179  return v8::Float64Array::New(array_buffer, start, size_ / 8);
180  default:
181  LOG(FATAL) << "Invalid enum value " << kind;
182  }
183 #elif defined(USING_JSC)
184  JSContextRef cx = GetContext();
185  LocalVar<JsObject> array_buffer = buffer_.handle();
186  size_t start = 0;
187  auto buffer_type = JSValueGetTypedArrayType(cx, array_buffer, nullptr);
188  DCHECK_NE(buffer_type, kJSTypedArrayTypeNone);
189  if (buffer_type != kJSTypedArrayTypeArrayBuffer) {
190  array_buffer = JSObjectGetTypedArrayBuffer(cx, buffer_.handle(), nullptr);
191  start = JSObjectGetTypedArrayByteOffset(cx, buffer_.handle(), nullptr);
192  }
193 
194  JSTypedArrayType jsc_kind;
195  size_t elem_size = 1;
196  switch (kind) {
197  case proto::ArrayBuffer:
198  return array_buffer;
199  case proto::Int8Array:
200  jsc_kind = kJSTypedArrayTypeInt8Array;
201  break;
202  case proto::Uint8Array:
203  jsc_kind = kJSTypedArrayTypeUint8Array;
204  break;
206  jsc_kind = kJSTypedArrayTypeUint8ClampedArray;
207  break;
208  case proto::Int16Array:
209  jsc_kind = kJSTypedArrayTypeInt16Array;
210  elem_size = 2;
211  break;
212  case proto::Uint16Array:
213  jsc_kind = kJSTypedArrayTypeUint16Array;
214  elem_size = 2;
215  break;
216  case proto::Int32Array:
217  jsc_kind = kJSTypedArrayTypeInt32Array;
218  elem_size = 4;
219  break;
220  case proto::Uint32Array:
221  jsc_kind = kJSTypedArrayTypeUint32Array;
222  elem_size = 4;
223  break;
224  case proto::Float32Array:
225  jsc_kind = kJSTypedArrayTypeFloat32Array;
226  elem_size = 4;
227  break;
228  case proto::Float64Array:
229  jsc_kind = kJSTypedArrayTypeFloat64Array;
230  elem_size = 8;
231  break;
232  default:
233  LOG(FATAL) << "Invalid enum value " << kind;
234  }
235  return JSObjectMakeTypedArrayWithArrayBufferAndOffset(
236  cx, jsc_kind, array_buffer, start, size_ / elem_size, nullptr);
237 #endif
238 }
239 
241  tracer->Trace(&buffer_);
242 }
243 
244 void ByteBuffer::ClearFields() {
245  buffer_.reset();
246  ptr_ = nullptr;
247  size_ = 0;
248  own_ptr_ = false;
249 }
250 
251 void ByteBuffer::ClearAndAllocateBuffer(size_t size) {
252  Clear();
253 
254  // Use malloc here, the same as in JsEngine::ArrayBufferAllocator.
255  // Must also be compatible with JSC (uses free()).
256  own_ptr_ = true;
257  size_ = size;
258  ptr_ = reinterpret_cast<uint8_t*>(std::malloc(size_)); // NOLINT
259  CHECK(ptr_);
260 }
261 
262 } // namespace shaka
void SetFromDynamicBuffer(const util::DynamicBuffer &other)
Definition: byte_buffer.cc:72
bool empty() const
Definition: weak_js_ptr.h:78
ReturnVal< JsValue > ToJsValue() const override
Definition: byte_buffer.cc:123
const uint8_t * data() const
Definition: byte_buffer.h:50
void CopyDataTo(uint8_t *dest, size_t size) const
ReturnVal< JsValue > value() const
Definition: weak_js_ptr.h:97
ExceptionCode type
void Trace(const Traceable *ptr)
Definition: heap_tracer.cc:43
ByteBuffer & operator=(const ByteBuffer &other)=delete
void SetFromBuffer(const void *buffer, size_t size)
Definition: byte_buffer.cc:77
size_t size() const
Definition: byte_buffer.h:55
void Trace(memory::HeapTracer *tracer) const override
Definition: byte_buffer.cc:240
JSContextRef GetContext()
Definition: jsc_utils.cc:24
Handle< T > handle() const
Definition: weak_js_ptr.h:87
v8::Isolate * GetIsolate()
Definition: v8_utils.cc:27
~ByteBuffer() override
Definition: byte_buffer.cc:49
bool TryConvert(Handle< JsValue > value) override
Definition: byte_buffer.cc:82