Shaka Player Embedded
backing_object_factory.cc
Go to the documentation of this file.
1 // Copyright 2017 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 "src/js/js_error.h"
18 
19 namespace shaka {
20 
21 namespace {
22 
23 ExceptionOr<void> NotImplementedCallback() {
25  "This feature is not implemented.");
26 }
27 
28 #ifdef USING_V8
29 
35 struct JsIndexerCallback {
36  static void GetIndex(uint32_t index,
37  const v8::PropertyCallbackInfo<v8::Value>& info) {
38  v8::HandleScope handle_scope(GetIsolate());
39  void* ptr = MaybeUnwrapPointer(info.Data());
40  if (!ptr) {
41  impl::ThrowError</* ReturnPromise */ false>::General(
42  nullptr, "", "", "INTERNAL: Invalid function data.");
43  return;
44  }
45  auto* factory = reinterpret_cast<BackingObjectFactoryBase*>(ptr);
46  info.GetReturnValue().Set(factory->GetIndex(info.This(), index));
47  }
48 
49  static void SetIndex(uint32_t index, v8::Local<v8::Value> given,
50  const v8::PropertyCallbackInfo<v8::Value>& info) {
51  v8::HandleScope handle_scope(GetIsolate());
52  void* ptr = MaybeUnwrapPointer(info.Data());
53  if (!ptr) {
54  impl::ThrowError</* ReturnPromise */ false>::General(
55  nullptr, "", "", "INTERNAL: Invalid function data.");
56  return;
57  }
58  auto* factory = reinterpret_cast<BackingObjectFactoryBase*>(ptr);
59  factory->SetIndex(info.This(), index, given);
60  }
61 };
62 
63 #elif defined(USING_JSC)
64 
65 bool TryGetIndex(JSStringRef name, size_t* index) {
66  JSContextRef cx = GetContext();
67  JSValueRef except = nullptr;
68  const double number =
69  JSValueToNumber(cx, JSValueMakeString(cx, name), &except);
70  if (except || isnan(number))
71  return false;
72  *index = static_cast<size_t>(number);
73  return true;
74 }
75 
76 JSValueRef GetProperty(JSContextRef cx, JSObjectRef target, JSStringRef name,
77  JSValueRef* except) {
78  // DCHECK_EQ(cx, GetContext());
79  auto* object = reinterpret_cast<BackingObject*>(JSObjectGetPrivate(target));
80  size_t index;
81  if (!TryGetIndex(name, &index))
82  return nullptr;
83  return object->factory()->GetIndex(target, index);
84 }
85 
86 bool SetProperty(JSContextRef cx, JSObjectRef target, JSStringRef name,
87  JSValueRef given, JSValueRef* except) {
88  // DCHECK_EQ(cx, GetContext());
89  auto* object = reinterpret_cast<BackingObject*>(JSObjectGetPrivate(target));
90  size_t index;
91  if (!TryGetIndex(name, &index))
92  return false;
93  object->factory()->SetIndex(target, index, given);
94  return true;
95 }
96 
97 #endif
98 
99 } // namespace
100 
102  const std::string& name, NativeCtor ctor,
103  const BackingObjectFactoryBase* base)
104  : type_name_(name), base_(base) {
105 #ifdef USING_V8
106  v8::Isolate* isolate = GetIsolate();
107 
108  const v8::Local<v8::Signature> empty_signature;
109  v8::Local<v8::FunctionTemplate> type = v8::FunctionTemplate::New(
110  isolate, ctor, v8::Local<v8::Value>(), empty_signature, 0);
111  type->SetClassName(JsStringFromUtf8(type_name_));
112  // We will store the pointer to the object in field 0. Field 1 must contain
113  // a valid pointer so the V8 GC will pass it to
114  // EmbedderHeapTracer::RegisterV8References.
115  // See: v8/src/heap/mark_compact.cc:2228.
116  type->InstanceTemplate()->SetInternalFieldCount(
118  if (base)
119  type->Inherit(base->class_definition_);
120 
121  // Add a callback for when the object is indexed.
122  v8::IndexedPropertyGetterCallback getter = &JsIndexerCallback::GetIndex;
123  v8::IndexedPropertySetterCallback setter = &JsIndexerCallback::SetIndex;
124  type->PrototypeTemplate()->SetIndexedPropertyHandler(
125  getter, setter, nullptr, nullptr, nullptr,
126  WrapPointer(static_cast<BackingObjectFactoryBase*>(this)));
127 
128  v8::MaybeLocal<v8::Function> maybe_ctor =
129  type->GetFunction(isolate->GetCurrentContext());
130  constructor_ = maybe_ctor.ToLocalChecked();
131  class_definition_ = type;
132  prototype_ = UnsafeJsCast<JsObject>(GetMemberRaw(constructor_, "prototype"));
133 
134  // Register the type on 'window'.
135  SetMemberRaw(JsEngine::Instance()->global_handle(), type_name_, constructor_);
136 #elif defined(USING_JSC)
137  memset(&definition_, 0, sizeof(definition_));
138  definition_.className = type_name_.c_str();
139  definition_.version = 1;
140  definition_.getProperty = &GetProperty;
141  definition_.setProperty = &SetProperty;
142  if (base)
143  definition_.parentClass = base->GetClass();
144 
145  JSContextRef cx = GetContext();
146  class_definition_ = JSClassCreate(&definition_);
147  constructor_ = JSObjectMakeConstructor(cx, class_definition_, ctor);
148  prototype_ = UnsafeJsCast<JsObject>(GetMemberRaw(constructor_, "prototype"));
149 
150  // Register the type on the global object.
151  SetMemberRaw(JSContextGetGlobalObject(cx), type_name_, constructor_);
152 #endif
153 }
154 
156 
157 bool BackingObjectFactoryBase::DerivedFrom(const std::string& name) const {
158  if (name == type_name_)
159  return true;
160  if (!base_)
161  return name == "BackingObject";
162  return base_->DerivedFrom(name);
163 }
164 
166  BackingObject* object) {
167  LocalVar<JsValue> result;
168  LocalVar<JsValue> args[] = {WrapPointer(object)};
169  CHECK(InvokeConstructor(constructor_, 1, args, &result));
170  return result;
171 }
172 
173 ReturnVal<JsValue> BackingObjectFactoryBase::GetIndex(Handle<JsObject> that,
174  size_t index) {
175  if (!indexer_)
176  return JsUndefined();
177  return indexer_->GetIndex(that, index);
178 }
179 
180 void BackingObjectFactoryBase::SetIndex(Handle<JsObject> that, size_t index,
181  Handle<JsValue> value) {
182  if (indexer_)
183  indexer_->SetIndex(that, index, value);
184 }
185 
186 void BackingObjectFactoryBase::NotImplemented(const std::string& name) {
187  LocalVar<JsFunction> getter = CreateStaticFunction(
188  type_name_, name,
189  std::function<ExceptionOr<void>()>(&NotImplementedCallback));
190  SetGenericPropertyRaw(prototype_, name, getter, getter);
191 }
192 
193 } // namespace shaka
ReturnVal< JsFunction > CreateStaticFunction(const std::string &target, const std::string &name, Func &&callback)
ReturnVal< JsValue > GetIndex(Handle< JsObject > that, size_t index)
ReturnVal< JsValue > JsUndefined()
Definition: js_wrappers.cc:284
const char * name
ExceptionCode type
void NotImplemented(const std::string &name)
BackingObjectFactoryBase(const std::string &name, NativeCtor ctor, const BackingObjectFactoryBase *base)
static constexpr const size_t kInternalFieldCount
void SetMemberRaw(Handle< JsObject > object, const std::string &name, Handle< JsValue > value)
Definition: js_wrappers.cc:147
void SetIndex(Handle< JsObject > that, size_t index, Handle< JsValue > value)
bool DerivedFrom(const std::string &name) const
static JsError DOMException(ExceptionCode code)
Definition: js_error.cc:115
JSContextRef GetContext()
Definition: jsc_utils.cc:24
ReturnVal< JsValue > WrapPointer(void *ptr)
Definition: js_wrappers.cc:213
ReturnVal< JsString > JsStringFromUtf8(const std::string &str)
Definition: js_wrappers.cc:266
ReturnVal< JsValue > WrapInstance(BackingObject *object)
bool InvokeConstructor(Handle< JsFunction > ctor, int argc, LocalVar< JsValue > *argv, LocalVar< JsValue > *result_or_except)
Definition: js_wrappers.cc:165
v8::Isolate * GetIsolate()
Definition: v8_utils.cc:27
ReturnVal< JsValue > GetMemberRaw(Handle< JsObject > object, const std::string &name, LocalVar< JsValue > *exception=nullptr)
Definition: js_wrappers.cc:136
void * MaybeUnwrapPointer(Handle< JsValue > value)
Definition: js_wrappers.cc:217
void SetGenericPropertyRaw(Handle< JsObject > object, const std::string &name, Handle< JsFunction > getter, Handle< JsFunction > setter)
Definition: js_wrappers.cc:158