// 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 file. #include "gin/wrappable.h" #include "base/check_op.h" #include "gin/object_template_builder.h" #include "gin/per_isolate_data.h" namespace gin { WrappableBase::WrappableBase() = default; WrappableBase::~WrappableBase() { wrapper_.Reset(); } ObjectTemplateBuilder WrappableBase::GetObjectTemplateBuilder( v8::Isolate* isolate) { return ObjectTemplateBuilder(isolate, GetTypeName()); } const char* WrappableBase::GetTypeName() { return nullptr; } void WrappableBase::FirstWeakCallback( const v8::WeakCallbackInfo& data) { WrappableBase* wrappable = data.GetParameter(); wrappable->dead_ = true; wrappable->wrapper_.Reset(); data.SetSecondPassCallback(SecondWeakCallback); } void WrappableBase::SecondWeakCallback( const v8::WeakCallbackInfo& data) { WrappableBase* wrappable = data.GetParameter(); delete wrappable; } v8::MaybeLocal WrappableBase::GetWrapperImpl(v8::Isolate* isolate, WrapperInfo* info) { if (!wrapper_.IsEmpty()) { return v8::MaybeLocal( v8::Local::New(isolate, wrapper_)); } if (dead_) return v8::MaybeLocal(); PerIsolateData* data = PerIsolateData::From(isolate); v8::Local templ = data->GetObjectTemplate(info); if (templ.IsEmpty()) { templ = GetObjectTemplateBuilder(isolate).Build(); CHECK(!templ.IsEmpty()); data->SetObjectTemplate(info, templ); } CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount()); v8::Local 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(wrapper); } int indices[] = {kWrapperInfoIndex, kEncodedValueIndex}; void* values[] = {info, this}; wrapper->SetAlignedPointerInInternalFields(2, indices, values); wrapper_.Reset(isolate, wrapper); wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter); return v8::MaybeLocal(wrapper); } namespace internal { void* FromV8Impl(v8::Isolate* isolate, v8::Local val, WrapperInfo* wrapper_info) { if (!val->IsObject()) return NULL; v8::Local obj = v8::Local::Cast(val); WrapperInfo* info = WrapperInfo::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 NULL; // 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 NULL; return obj->GetAlignedPointerFromInternalField(kEncodedValueIndex); } } // namespace internal } // namespace gin