2014-04-15 11:04:36 +08:00
|
|
|
// Copyright 2013 The Chromium Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE.chromium file.
|
|
|
|
|
2019-12-05 18:46:34 +09:00
|
|
|
#include "shell/common/gin_helper/wrappable.h"
|
2014-04-15 11:04:36 +08:00
|
|
|
|
2025-08-08 22:00:45 -06:00
|
|
|
#include "gin/object_template_builder.h"
|
2025-01-30 03:20:37 +09:00
|
|
|
#include "gin/public/isolate_holder.h"
|
2019-12-05 18:46:34 +09:00
|
|
|
#include "shell/common/gin_helper/dictionary.h"
|
2024-07-29 12:42:57 -05:00
|
|
|
#include "v8/include/v8-function.h"
|
2014-04-15 11:04:36 +08:00
|
|
|
|
2019-12-05 18:46:34 +09:00
|
|
|
namespace gin_helper {
|
2014-04-15 11:04:36 +08:00
|
|
|
|
2025-04-17 15:09:48 +02:00
|
|
|
bool IsValidWrappable(const v8::Local<v8::Value>& val,
|
2025-07-15 12:05:29 -04:00
|
|
|
const gin::DeprecatedWrapperInfo* wrapper_info) {
|
2025-04-17 15:09:48 +02:00
|
|
|
if (!val->IsObject())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
v8::Local<v8::Object> port = val.As<v8::Object>();
|
|
|
|
if (port->InternalFieldCount() != gin::kNumberOfInternalFields)
|
|
|
|
return false;
|
|
|
|
|
2025-07-15 12:05:29 -04:00
|
|
|
const gin::DeprecatedWrapperInfo* info =
|
|
|
|
static_cast<gin::DeprecatedWrapperInfo*>(
|
|
|
|
port->GetAlignedPointerFromInternalField(gin::kWrapperInfoIndex));
|
2025-04-17 15:09:48 +02:00
|
|
|
if (info != wrapper_info)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-26 02:16:28 +02:00
|
|
|
WrappableBase::WrappableBase() = default;
|
2014-04-15 11:04:36 +08:00
|
|
|
|
2016-04-25 10:17:39 +09:00
|
|
|
WrappableBase::~WrappableBase() {
|
2017-04-12 15:51:28 +02:00
|
|
|
if (wrapper_.IsEmpty())
|
|
|
|
return;
|
2017-11-27 00:50:51 +01:00
|
|
|
|
2020-03-10 18:16:58 -07:00
|
|
|
v8::HandleScope scope(isolate());
|
2017-04-12 15:51:28 +02:00
|
|
|
GetWrapper()->SetAlignedPointerInInternalField(0, nullptr);
|
|
|
|
wrapper_.ClearWeak();
|
2015-08-27 15:50:38 +08:00
|
|
|
wrapper_.Reset();
|
2014-04-15 11:04:36 +08:00
|
|
|
}
|
|
|
|
|
2018-02-20 09:29:02 +09:00
|
|
|
v8::Local<v8::Object> WrappableBase::GetWrapper() const {
|
2017-10-23 23:19:23 -07:00
|
|
|
if (!wrapper_.IsEmpty())
|
|
|
|
return v8::Local<v8::Object>::New(isolate_, wrapper_);
|
|
|
|
else
|
2024-11-26 18:41:46 -06:00
|
|
|
return {};
|
2016-04-25 10:17:39 +09:00
|
|
|
}
|
2014-04-22 15:57:23 +08:00
|
|
|
|
2019-10-15 10:15:23 +09:00
|
|
|
void WrappableBase::InitWithArgs(gin::Arguments* args) {
|
|
|
|
v8::Local<v8::Object> holder;
|
|
|
|
args->GetHolder(&holder);
|
|
|
|
InitWith(args->isolate(), holder);
|
|
|
|
}
|
|
|
|
|
2016-04-25 10:17:39 +09:00
|
|
|
void WrappableBase::InitWith(v8::Isolate* isolate,
|
|
|
|
v8::Local<v8::Object> wrapper) {
|
|
|
|
CHECK(wrapper_.IsEmpty());
|
2015-06-23 17:08:52 +08:00
|
|
|
isolate_ = isolate;
|
2015-08-27 15:50:38 +08:00
|
|
|
wrapper->SetAlignedPointerInInternalField(0, this);
|
|
|
|
wrapper_.Reset(isolate, wrapper);
|
2020-03-10 18:16:58 -07:00
|
|
|
wrapper_.SetWeak(this, FirstWeakCallback,
|
|
|
|
v8::WeakCallbackType::kInternalFields);
|
2017-11-27 00:50:51 +01:00
|
|
|
|
2014-05-27 08:47:06 +08:00
|
|
|
// Call object._init if we have one.
|
2015-05-22 19:11:02 +08:00
|
|
|
v8::Local<v8::Function> init;
|
2014-05-27 08:47:06 +08:00
|
|
|
if (Dictionary(isolate, wrapper).Get("_init", &init))
|
2019-03-21 00:27:06 +09:00
|
|
|
init->Call(isolate->GetCurrentContext(), wrapper, 0, nullptr).IsEmpty();
|
2014-04-16 10:36:54 +08:00
|
|
|
}
|
|
|
|
|
2014-04-16 11:58:17 +08:00
|
|
|
// static
|
2016-04-25 10:17:39 +09:00
|
|
|
void WrappableBase::FirstWeakCallback(
|
|
|
|
const v8::WeakCallbackInfo<WrappableBase>& data) {
|
2025-01-30 03:20:37 +09:00
|
|
|
WrappableBase* wrappable = data.GetParameter();
|
|
|
|
auto* wrappable_from_field =
|
|
|
|
static_cast<WrappableBase*>(data.GetInternalField(0));
|
|
|
|
if (wrappable && wrappable == wrappable_from_field) {
|
2020-03-10 18:16:58 -07:00
|
|
|
wrappable->wrapper_.Reset();
|
|
|
|
data.SetSecondPassCallback(SecondWeakCallback);
|
|
|
|
}
|
2015-08-27 15:50:38 +08:00
|
|
|
}
|
|
|
|
|
2016-04-25 10:17:39 +09:00
|
|
|
// static
|
|
|
|
void WrappableBase::SecondWeakCallback(
|
|
|
|
const v8::WeakCallbackInfo<WrappableBase>& data) {
|
2025-01-30 03:20:37 +09:00
|
|
|
if (gin::IsolateHolder::DestroyedMicrotasksRunner()) {
|
|
|
|
return;
|
|
|
|
}
|
2021-05-27 13:15:25 -07:00
|
|
|
delete static_cast<WrappableBase*>(data.GetInternalField(0));
|
2014-04-15 11:04:36 +08:00
|
|
|
}
|
|
|
|
|
2025-08-08 22:00:45 -06:00
|
|
|
DeprecatedWrappableBase::DeprecatedWrappableBase() = default;
|
|
|
|
|
|
|
|
DeprecatedWrappableBase::~DeprecatedWrappableBase() {
|
|
|
|
if (!wrapper_.IsEmpty())
|
|
|
|
wrapper_.ClearWeak();
|
|
|
|
wrapper_.Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
gin::ObjectTemplateBuilder DeprecatedWrappableBase::GetObjectTemplateBuilder(
|
|
|
|
v8::Isolate* isolate) {
|
|
|
|
return gin::ObjectTemplateBuilder(isolate, GetTypeName());
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* DeprecatedWrappableBase::GetTypeName() {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeprecatedWrappableBase::FirstWeakCallback(
|
|
|
|
const v8::WeakCallbackInfo<DeprecatedWrappableBase>& data) {
|
|
|
|
DeprecatedWrappableBase* wrappable = data.GetParameter();
|
|
|
|
DeprecatedWrappableBase* wrappable_from_field =
|
|
|
|
static_cast<DeprecatedWrappableBase*>(data.GetInternalField(1));
|
|
|
|
if (wrappable && wrappable == wrappable_from_field) {
|
|
|
|
wrappable->dead_ = true;
|
|
|
|
wrappable->wrapper_.Reset();
|
|
|
|
data.SetSecondPassCallback(SecondWeakCallback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeprecatedWrappableBase::SecondWeakCallback(
|
|
|
|
const v8::WeakCallbackInfo<DeprecatedWrappableBase>& data) {
|
|
|
|
if (gin::IsolateHolder::DestroyedMicrotasksRunner())
|
|
|
|
return;
|
|
|
|
DeprecatedWrappableBase* wrappable = data.GetParameter();
|
|
|
|
if (wrappable)
|
|
|
|
delete wrappable;
|
|
|
|
}
|
|
|
|
|
|
|
|
v8::MaybeLocal<v8::Object> DeprecatedWrappableBase::GetWrapperImpl(
|
|
|
|
v8::Isolate* isolate,
|
|
|
|
gin::DeprecatedWrapperInfo* info) {
|
|
|
|
if (!wrapper_.IsEmpty()) {
|
|
|
|
return v8::MaybeLocal<v8::Object>(
|
|
|
|
v8::Local<v8::Object>::New(isolate, wrapper_));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dead_) {
|
|
|
|
return v8::MaybeLocal<v8::Object>();
|
|
|
|
}
|
|
|
|
|
|
|
|
gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
|
|
|
|
v8::Local<v8::ObjectTemplate> templ = data->DeprecatedGetObjectTemplate(info);
|
|
|
|
if (templ.IsEmpty()) {
|
|
|
|
templ = GetObjectTemplateBuilder(isolate).Build();
|
|
|
|
CHECK(!templ.IsEmpty());
|
|
|
|
data->DeprecatedSetObjectTemplate(info, templ);
|
|
|
|
}
|
|
|
|
CHECK_EQ(gin::kNumberOfInternalFields, templ->InternalFieldCount());
|
|
|
|
v8::Local<v8::Object> wrapper;
|
|
|
|
// |wrapper| may be empty in some extreme cases, e.g., when
|
|
|
|
// Object.prototype.constructor is overwritten.
|
|
|
|
if (!templ->NewInstance(isolate->GetCurrentContext()).ToLocal(&wrapper)) {
|
|
|
|
// The current wrappable object will be no longer managed by V8. Delete this
|
|
|
|
// now.
|
|
|
|
delete this;
|
|
|
|
return v8::MaybeLocal<v8::Object>(wrapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
int indices[] = {gin::kWrapperInfoIndex, gin::kEncodedValueIndex};
|
|
|
|
void* values[] = {info, this};
|
|
|
|
wrapper->SetAlignedPointerInInternalFields(2, indices, values);
|
|
|
|
wrapper_.Reset(isolate, wrapper);
|
|
|
|
wrapper_.SetWeak(this, FirstWeakCallback,
|
|
|
|
v8::WeakCallbackType::kInternalFields);
|
|
|
|
return v8::MaybeLocal<v8::Object>(wrapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeprecatedWrappableBase::ClearWeak() {
|
|
|
|
if (!wrapper_.IsEmpty())
|
|
|
|
wrapper_.ClearWeak();
|
|
|
|
}
|
|
|
|
|
2014-04-15 11:04:36 +08:00
|
|
|
namespace internal {
|
|
|
|
|
2015-05-22 19:11:02 +08:00
|
|
|
void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val) {
|
2014-04-15 11:04:36 +08:00
|
|
|
if (!val->IsObject())
|
2016-04-25 10:17:39 +09:00
|
|
|
return nullptr;
|
2021-05-12 09:38:21 +02:00
|
|
|
v8::Local<v8::Object> obj = val.As<v8::Object>();
|
2015-02-11 22:09:42 +08:00
|
|
|
if (obj->InternalFieldCount() != 1)
|
2016-04-25 10:17:39 +09:00
|
|
|
return nullptr;
|
|
|
|
return obj->GetAlignedPointerFromInternalField(0);
|
2014-04-15 11:04:36 +08:00
|
|
|
}
|
|
|
|
|
2025-08-08 22:00:45 -06:00
|
|
|
void* FromV8Impl(v8::Isolate* isolate,
|
|
|
|
v8::Local<v8::Value> val,
|
|
|
|
gin::DeprecatedWrapperInfo* wrapper_info) {
|
|
|
|
if (!val->IsObject()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(val);
|
|
|
|
gin::DeprecatedWrapperInfo* info = gin::DeprecatedWrapperInfo::From(obj);
|
|
|
|
|
|
|
|
// If this fails, the object is not managed by Gin. It is either a normal JS
|
|
|
|
// object that's not wrapping any external C++ object, or it is wrapping some
|
|
|
|
// C++ object, but that object isn't managed by Gin (maybe Blink).
|
|
|
|
if (!info) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this fails, the object is managed by Gin, but it's not wrapping an
|
|
|
|
// instance of the C++ class associated with wrapper_info.
|
|
|
|
if (info != wrapper_info) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj->GetAlignedPointerFromInternalField(gin::kEncodedValueIndex);
|
|
|
|
}
|
|
|
|
|
2014-04-15 11:04:36 +08:00
|
|
|
} // namespace internal
|
|
|
|
|
2019-12-05 18:46:34 +09:00
|
|
|
} // namespace gin_helper
|
2025-08-11 14:01:08 -06:00
|
|
|
|
|
|
|
namespace gin {
|
|
|
|
|
|
|
|
DeprecatedWrapperInfo* DeprecatedWrapperInfo::From(
|
|
|
|
v8::Local<v8::Object> object) {
|
|
|
|
if (object->InternalFieldCount() != kNumberOfInternalFields)
|
|
|
|
return NULL;
|
|
|
|
DeprecatedWrapperInfo* info = static_cast<DeprecatedWrapperInfo*>(
|
|
|
|
object->GetAlignedPointerFromInternalField(kWrapperInfoIndex));
|
|
|
|
return info->embedder == kEmbedderNativeGin ? info : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace gin
|