| // Copyright 2017 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef COBALT_SCRIPT_V8C_V8C_USER_OBJECT_HOLDER_H_ |
| #define COBALT_SCRIPT_V8C_V8C_USER_OBJECT_HOLDER_H_ |
| |
| #include <memory> |
| |
| #include "cobalt/script/script_value.h" |
| #include "cobalt/script/v8c/v8c_engine.h" |
| #include "cobalt/script/v8c/v8c_global_environment.h" |
| #include "cobalt/script/v8c/wrapper_private.h" |
| #include "v8/include/v8.h" |
| |
| namespace cobalt { |
| namespace script { |
| namespace v8c { |
| |
| // Template class that implements the ScriptValue template class for lifetime |
| // management of User Objects passed from the bindings layer into Cobalt. See |
| // the definition of ScriptValue for further detail. |
| // This class does not root the underlying v8::Object that V8cUserObjectType |
| // holds a reference to. The object will be traced when any owning objects are |
| // traced. |
| // |
| // |V8cUserObjectType| should be a |ScopedPersistent<v8::Value>|. |
| template <typename V8cUserObjectType> |
| class V8cUserObjectHolder |
| : public ScriptValue<typename V8cUserObjectType::BaseType> { |
| public: |
| typedef ScriptValue<typename V8cUserObjectType::BaseType> BaseClass; |
| |
| V8cUserObjectHolder() = default; |
| V8cUserObjectHolder(v8::Isolate* isolate, v8::Local<v8::Value> value) |
| : isolate_(isolate), |
| handle_(isolate, value), |
| prevent_garbage_collection_count_(0) { |
| } |
| V8cUserObjectHolder(const V8cUserObjectHolder&) = delete; |
| V8cUserObjectHolder& operator=(const V8cUserObjectHolder&) = delete; |
| V8cUserObjectHolder(V8cUserObjectHolder&& other) |
| : isolate_(other.isolate_), |
| handle_(other.isolate_, other.v8_value()), |
| prevent_garbage_collection_count_( |
| other.prevent_garbage_collection_count_) { |
| other.isolate_ = nullptr; |
| other.handle_.Clear(); |
| other.prevent_garbage_collection_count_ = 0; |
| } |
| V8cUserObjectHolder& operator=(V8cUserObjectHolder&& other) { |
| isolate_ = other.isolate_; |
| handle_.Set(isolate_, other.v8_value()); |
| prevent_garbage_collection_count_ = other.prevent_garbage_collection_count_; |
| other.isolate_ = nullptr; |
| other.handle_.Clear(); |
| other.prevent_garbage_collection_count_ = 0; |
| return *this; |
| } |
| |
| bool EqualTo(const BaseClass& other) const override { |
| v8::HandleScope handle_scope(isolate_); |
| const V8cUserObjectHolder* v8c_other = |
| base::polymorphic_downcast<const V8cUserObjectHolder*>(&other); |
| return v8_value() == v8c_other->v8_value(); |
| } |
| |
| void RegisterOwner(Wrappable* owner) override { |
| V8cEngine::GetFromIsolate(isolate_)->heap_tracer()->AddReferencedObject( |
| owner, &handle_); |
| } |
| |
| void DeregisterOwner(Wrappable* owner) override { |
| // This will get called in destructors caused by finalizers caused by the |
| // final shutdown GC. In this case, the entire heap tracer will have |
| // already been removed, so we don't need to bother removing ourselves. |
| V8cHeapTracer* tracer = V8cEngine::GetFromIsolate(isolate_)->heap_tracer(); |
| if (tracer) { |
| tracer->RemoveReferencedObject(owner, &handle_); |
| } |
| } |
| |
| void PreventGarbageCollection() override { |
| if (prevent_garbage_collection_count_++ == 0 && !handle_.IsEmpty()) { |
| V8cHeapTracer* tracer = |
| V8cEngine::GetFromIsolate(isolate_)->heap_tracer(); |
| if (tracer) { |
| tracer->AddRoot(handle_.traced_global_ptr()); |
| } |
| } |
| } |
| |
| void AllowGarbageCollection() override { |
| DCHECK_GT(prevent_garbage_collection_count_, 0); |
| if (--prevent_garbage_collection_count_ == 0 && !handle_.IsEmpty()) { |
| V8cHeapTracer* tracer = |
| V8cEngine::GetFromIsolate(isolate_)->heap_tracer(); |
| if (tracer) { |
| tracer->RemoveRoot(handle_.traced_global_ptr()); |
| } |
| } |
| } |
| |
| typename V8cUserObjectType::BaseType* GetValue() override { |
| return const_cast<typename V8cUserObjectType::BaseType*>( |
| static_cast<const V8cUserObjectHolder&>(*this).GetValue()); |
| } |
| |
| const typename V8cUserObjectType::BaseType* GetValue() const override { |
| return handle_.IsEmpty() ? nullptr : &handle_; |
| } |
| |
| std::unique_ptr<BaseClass> MakeCopy() const override { |
| v8::HandleScope handle_scope(isolate_); |
| return std::unique_ptr<BaseClass>( |
| new V8cUserObjectHolder(isolate_, v8_value())); |
| } |
| |
| v8::Local<v8::Value> v8_value() const { return handle_.NewLocal(isolate_); } |
| |
| v8::Isolate* isolate() const { return isolate_; } |
| |
| private: |
| v8::Isolate* isolate_ = nullptr; |
| V8cUserObjectType handle_{}; |
| int prevent_garbage_collection_count_ = 0; |
| }; |
| |
| } // namespace v8c |
| } // namespace script |
| } // namespace cobalt |
| |
| #endif // COBALT_SCRIPT_V8C_V8C_USER_OBJECT_HOLDER_H_ |