// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gin/object_template_builder.h" #include #include #include "gin/interceptor.h" #include "gin/per_isolate_data.h" #include "gin/public/wrapper_info.h" #include "v8/include/v8-exception.h" #include "v8/include/v8-template.h" namespace gin { namespace { WrappableBase* WrappableFromV8(v8::Isolate* isolate, v8::Local val) { if (!val->IsObject()) { return nullptr; } v8::Local obj = v8::Local::Cast(val); WrapperInfo* info = WrapperInfo::From(obj); // If this fails, the object is not managed by Gin. if (!info) { return nullptr; } // We don't further validate the type of the object, but assume it's derived // from WrappableBase. We look up the pointer in a global registry, to make // sure it's actually pointed to a valid life object. return static_cast( obj->GetAlignedPointerFromInternalField(kEncodedValueIndex)); } NamedPropertyInterceptor* NamedInterceptorFromV8(v8::Isolate* isolate, v8::Local val) { WrappableBase* base = WrappableFromV8(isolate, val); if (!base) { return nullptr; } return PerIsolateData::From(isolate)->GetNamedPropertyInterceptor(base); } IndexedPropertyInterceptor* IndexedInterceptorFromV8( v8::Isolate* isolate, v8::Local val) { WrappableBase* base = WrappableFromV8(isolate, val); if (!base) { return nullptr; } return PerIsolateData::From(isolate)->GetIndexedPropertyInterceptor(base); } v8::Intercepted NamedPropertyGetter( v8::Local property, const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); NamedPropertyInterceptor* interceptor = NamedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) { return v8::Intercepted::kNo; } std::string name; ConvertFromV8(isolate, property, &name); v8::Local result = interceptor->GetNamedProperty(isolate, name); if (!result.IsEmpty()) { info.GetReturnValue().SetNonEmpty(result); return v8::Intercepted::kYes; } return v8::Intercepted::kNo; } v8::Intercepted NamedPropertySetter( v8::Local property, v8::Local value, const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); NamedPropertyInterceptor* interceptor = NamedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) { return v8::Intercepted::kNo; } std::string name; ConvertFromV8(isolate, property, &name); if (interceptor->SetNamedProperty(isolate, name, value)) { return v8::Intercepted::kYes; } return v8::Intercepted::kNo; } v8::Intercepted NamedPropertyQuery( v8::Local property, const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); NamedPropertyInterceptor* interceptor = NamedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) { return v8::Intercepted::kNo; } std::string name; ConvertFromV8(isolate, property, &name); if (!interceptor->GetNamedProperty(isolate, name).IsEmpty()) { info.GetReturnValue().Set(v8::None); return v8::Intercepted::kYes; } return v8::Intercepted::kNo; } void NamedPropertyEnumerator(const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); NamedPropertyInterceptor* interceptor = NamedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) { return; } v8::Local properties; if (!TryConvertToV8(isolate, interceptor->EnumerateNamedProperties(isolate), &properties)) { return; } info.GetReturnValue().Set(v8::Local::Cast(properties)); } v8::Intercepted IndexedPropertyQuery( uint32_t index, const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); IndexedPropertyInterceptor* interceptor = IndexedInterceptorFromV8(isolate, info.Holder()); if (interceptor && !interceptor->GetIndexedProperty(isolate, index).IsEmpty()) { info.GetReturnValue().Set(v8::None); return v8::Intercepted::kYes; } return v8::Intercepted::kNo; } v8::Intercepted IndexedPropertyGetter( uint32_t index, const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); IndexedPropertyInterceptor* interceptor = IndexedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) { return v8::Intercepted::kNo; } v8::Local result = interceptor->GetIndexedProperty(isolate, index); if (!result.IsEmpty()) { info.GetReturnValue().SetNonEmpty(result); return v8::Intercepted::kYes; } return v8::Intercepted::kNo; } v8::Intercepted IndexedPropertySetter( uint32_t index, v8::Local value, const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); IndexedPropertyInterceptor* interceptor = IndexedInterceptorFromV8(isolate, info.Holder()); if (interceptor && interceptor->SetIndexedProperty(isolate, index, value)) { return v8::Intercepted::kYes; } return v8::Intercepted::kNo; } void IndexedPropertyEnumerator( const v8::PropertyCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); IndexedPropertyInterceptor* interceptor = IndexedInterceptorFromV8(isolate, info.Holder()); if (!interceptor) { return; } v8::Local properties; if (!TryConvertToV8(isolate, interceptor->EnumerateIndexedProperties(isolate), &properties)) { return; } info.GetReturnValue().Set(v8::Local::Cast(properties)); } void Constructor(const v8::FunctionCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); isolate->ThrowException(v8::Exception::Error(info.Data().As())); } } // namespace ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate) : ObjectTemplateBuilder(isolate, nullptr) {} ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate, const char* type_name) : isolate_(isolate), type_name_(type_name), constructor_template_(v8::FunctionTemplate::New( isolate, &Constructor, StringToV8( isolate, type_name ? base::StrCat({"Objects of type ", type_name, " cannot be created using the constructor."}) : "Objects of this type cannot be created using the " "constructor"))), template_(constructor_template_->InstanceTemplate()) { template_->SetInternalFieldCount(kNumberOfInternalFields); } ObjectTemplateBuilder::ObjectTemplateBuilder( const ObjectTemplateBuilder& other) = default; ObjectTemplateBuilder::~ObjectTemplateBuilder() = default; ObjectTemplateBuilder& ObjectTemplateBuilder::AddNamedPropertyInterceptor() { template_->SetHandler(v8::NamedPropertyHandlerConfiguration( &NamedPropertyGetter, &NamedPropertySetter, &NamedPropertyQuery, nullptr, &NamedPropertyEnumerator, v8::Local(), v8::PropertyHandlerFlags::kOnlyInterceptStrings)); return *this; } ObjectTemplateBuilder& ObjectTemplateBuilder::AddIndexedPropertyInterceptor() { template_->SetHandler(v8::IndexedPropertyHandlerConfiguration( &IndexedPropertyGetter, &IndexedPropertySetter, &IndexedPropertyQuery, nullptr, &IndexedPropertyEnumerator, v8::Local())); return *this; } ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl( const std::string_view& name, v8::Local val) { template_->Set(StringToSymbol(isolate_, name), val); return *this; } ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl(v8::Local name, v8::Local val) { template_->Set(name, val); return *this; } ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl( const std::string_view& name, v8::Local getter, v8::Local setter) { template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter, setter); return *this; } ObjectTemplateBuilder& ObjectTemplateBuilder::SetLazyDataPropertyImpl( const std::string_view& name, v8::AccessorNameGetterCallback callback, v8::Local data) { template_->SetLazyDataProperty(StringToSymbol(isolate_, name), callback, data); return *this; } v8::Local ObjectTemplateBuilder::Build() { v8::Local result = template_; template_.Clear(); constructor_template_.Clear(); return result; } } // namespace gin