blob: 0a6a07561a9339e6ef545a23f25449458e0dcc68 [file] [log] [blame]
// Copyright 2017 Google Inc. 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_WRAPPER_PRIVATE_H_
#define COBALT_SCRIPT_V8C_WRAPPER_PRIVATE_H_
#include "base/memory/weak_ptr.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "v8/include/v8.h"
namespace cobalt {
namespace script {
namespace v8c {
// Contains private data associated with a v8::Object representing a
// JavaScript wrapper for a Cobalt platform object. There should be a one-to-
// one mapping of such v8::Object and WrapperPrivate instances, and the
// corresponding |WrapperPrivate| must be destroyed when its |v8::Object| is
// garbage collected.
class WrapperPrivate : public base::SupportsWeakPtr<WrapperPrivate> {
public:
// The callback that V8 will run when the |v8::Object| that we live inside
// of dies.
static void Callback(const v8::WeakCallbackInfo<WrapperPrivate>& data) {
delete data.GetParameter();
}
// Get the internal |WrapperPrivate*| data within |object|. This function
// should never be called on objects that don't have private data.
static WrapperPrivate* GetFromWrapperObject(v8::Local<v8::Object> object) {
DCHECK(object->InternalFieldCount() == kInternalFieldCount);
return static_cast<WrapperPrivate*>(
object->GetAlignedPointerFromInternalField(kInternalFieldDataIndex));
}
// Check whether |object| has private wrapper data.
static bool HasWrapperPrivate(v8::Local<v8::Object> object) {
return object->InternalFieldCount() == kInternalFieldCount;
}
// The total amount of internal fields in |wrapper_| we use. See
// |kInternalFieldDataIndex| and |kInternalFieldDummyIndex| below for
// further information.
static const int kInternalFieldCount = 2;
// Start at 1009 out of paranoia that we will collide with V8 looking for
// Blink specific class ids in the future.
static const int kClassId = 1009;
WrapperPrivate() = delete;
WrapperPrivate(v8::Isolate* isolate,
const scoped_refptr<Wrappable>& wrappable,
v8::Local<v8::Object> wrapper)
: isolate_(isolate), wrappable_(wrappable), wrapper_(isolate, wrapper) {
wrapper->SetAlignedPointerInInternalField(kInternalFieldDataIndex, this);
wrapper->SetAlignedPointerInInternalField(kInternalFieldDummyIndex,
nullptr);
wrapper_.SetWeak(this, &WrapperPrivate::Callback,
v8::WeakCallbackType::kParameter);
wrapper_.SetWrapperClassId(kClassId);
}
~WrapperPrivate() {
DCHECK(wrapper_.IsNearDeath());
DCHECK_EQ(ref_count_, 0);
wrapper_.ClearWeak();
wrapper_.Reset();
}
// Mark |wrapper_| as reachable from other |Traceable|s. This will be
// called by |V8cHeapTracer| during tracing.
void Mark() { wrapper_.RegisterExternalReference(isolate_); }
template <typename T>
scoped_refptr<T> wrappable() const {
return base::polymorphic_downcast<T*>(wrappable_.get());
}
Wrappable* raw_wrappable() const { return wrappable_.get(); }
v8::Local<v8::Object> wrapper() const { return wrapper_.Get(isolate_); }
void IncrementRefCount() {
DCHECK_GE(ref_count_, 0);
ref_count_++;
wrapper_.ClearWeak();
}
void DecrementRefCount() {
DCHECK_GT(ref_count_, 0);
if (--ref_count_ == 0) {
wrapper_.SetWeak(this, &WrapperPrivate::Callback,
v8::WeakCallbackType::kParameter);
}
}
// This should only be called for the special case of shutdown, where we
// want to keep nothing alive and run all finalizers.
void ForceWeakForShutDown() {
ref_count_ = 0;
wrapper_.SetWeak(this, &WrapperPrivate::Callback,
v8::WeakCallbackType::kParameter);
}
private:
// For the time being, we only use a single internal field, which stores a
// pointer back to us (us being the |WrapperPrivate|).
static const int kInternalFieldDataIndex = 0;
// Blink uses two fields, so V8 won't believe we're a potential wrapper
// unless we have two fields.
// .-""""""-.
// .' '.
// / O O \
// : :
// | |
// : .------. :
// \ ' ' /
// '. .'
// '-......-'
static const int kInternalFieldDummyIndex = 1;
v8::Isolate* isolate_;
scoped_refptr<Wrappable> wrappable_;
v8::Global<v8::Object> wrapper_;
int ref_count_ = 0;
DISALLOW_COPY_AND_ASSIGN(WrapperPrivate);
};
} // namespace v8c
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_V8C_WRAPPER_PRIVATE_H_