commit ff65b7dae1f56ea5f3e1b84e9740f301fdf508a0 Author: Cheng Zhao Date: Tue Apr 15 11:04:36 2014 +0800 Initial commit. diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..5f39f8bd9553 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2014 Cheng Zhao. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE.chromium b/LICENSE.chromium new file mode 100644 index 000000000000..972bb2edb099 --- /dev/null +++ b/LICENSE.chromium @@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/native_mate/arguments.cc b/native_mate/arguments.cc new file mode 100644 index 000000000000..70351479a022 --- /dev/null +++ b/native_mate/arguments.cc @@ -0,0 +1,48 @@ +// 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. + +#include "native_mate/arguments.h" + +#include "base/strings/stringprintf.h" +#include "native_mate/converter.h" + +namespace mate { + +Arguments::Arguments() + : isolate_(NULL), + info_(NULL), + next_(0), + insufficient_arguments_(false) { +} + +Arguments::Arguments(const MATE_METHOD_ARGS_TYPE& info) + : isolate_(info.GetIsolate()), + info_(&info), + next_(0), + insufficient_arguments_(false) { +} + +Arguments::~Arguments() { +} + +v8::Handle Arguments::PeekNext() const { + if (next_ >= info_->Length()) + return v8::Handle(); + return (*info_)[next_]; +} + +void Arguments::ThrowError() const { + if (insufficient_arguments_) + return ThrowTypeError("Insufficient number of arguments."); + + ThrowTypeError(base::StringPrintf( + "Error processing argument %d.", next_ - 1)); +} + +void Arguments::ThrowTypeError(const std::string& message) const { + MATE_THROW_EXCEPTION(isolate_, v8::Exception::TypeError( + StringToV8(isolate_, message))); +} + +} // namespace mate diff --git a/native_mate/arguments.h b/native_mate/arguments.h new file mode 100644 index 000000000000..054e03abf84c --- /dev/null +++ b/native_mate/arguments.h @@ -0,0 +1,82 @@ +// 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. + +#ifndef NATIVE_MATE_ARGUMENTS_H_ +#define NATIVE_MATE_ARGUMENTS_H_ + +#include "base/basictypes.h" +#include "native_mate/compat.h" +#include "native_mate/converter.h" + +namespace mate { + +// Arguments is a wrapper around v8::FunctionCallbackInfo that integrates +// with Converter to make it easier to marshall arguments and return values +// between V8 and C++. +class Arguments { + public: + Arguments(); + explicit Arguments(const MATE_METHOD_ARGS_TYPE& info); + ~Arguments(); + + template + bool GetHolder(T* out) { + return ConvertFromV8(isolate_, info_->Holder(), out); + } + + template + bool GetData(T* out) { + return ConvertFromV8(isolate_, info_->Data(), out); + } + + template + bool GetNext(T* out) { + if (next_ >= info_->Length()) { + insufficient_arguments_ = true; + return false; + } + v8::Handle val = (*info_)[next_++]; + return ConvertFromV8(isolate_, val, out); + } + + template + bool GetRemaining(std::vector* out) { + if (next_ >= info_->Length()) { + insufficient_arguments_ = true; + return false; + } + int remaining = info_->Length() - next_; + out->resize(remaining); + for (int i = 0; i < remaining; ++i) { + v8::Handle val = (*info_)[next_++]; + if (!ConvertFromV8(isolate_, val, &out->at(i))) + return false; + } + return true; + } + +#if NODE_VERSION_AT_LEAST(0, 11, 0) + template + void Return(T val) { + info_->GetReturnValue().Set(ConvertToV8(isolate_, val)); + } +#endif + + v8::Handle PeekNext() const; + + void ThrowError() const; + void ThrowTypeError(const std::string& message) const; + + v8::Isolate* isolate() const { return isolate_; } + + private: + v8::Isolate* isolate_; + const MATE_METHOD_ARGS_TYPE* info_; + int next_; + bool insufficient_arguments_; +}; + +} // namespace mate + +#endif // NATIVE_MATE_ARGUMENTS_H_ diff --git a/native_mate/compat.h b/native_mate/compat.h new file mode 100644 index 000000000000..5641613c42e2 --- /dev/null +++ b/native_mate/compat.h @@ -0,0 +1,100 @@ +// Copyright 2014 Cheng Zhao. All rights reserved. +// Use of this source code is governed by MIT license that can be found in the +// LICENSE file. + +#ifndef NATIVE_MATE_COMPAT_H_ +#define NATIVE_MATE_COMPAT_H_ + +#include "node_version.h" + +#if (NODE_MODULE_VERSION > 0x000B) // Node 0.11+ + +#define MATE_HANDLE_SCOPE(isolate) v8::HandleScope handle_scope(isolate) + +#define MATE_METHOD_ARGS_TYPE v8::FunctionCallbackInfo +#define MATE_METHOD_RETURN_TYPE void + +#define MATE_METHOD_RETURN_VALUE(value) return info.GetReturnValue().Set(value) +#define MATE_METHOD_RETURN_UNDEFINED() return +#define MATE_METHOD_RETURN_NULL() return info.GetReturnValue().SetNull() +#define MATE_METHOD_RETURN(value) args.Return(value) + +#define MATE_STRING_NEW_FROM_UTF8(isolate, data, length) \ + v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString, length) +#define MATE_STRING_NEW_SYMBOL(isolate, data, length) \ + v8::String::NewFromUtf8(isolate, data, v8::String::kInternalizedString, length) + +#define MATE_SET_INTERNAL_FIELD_POINTER(object, index, value) \ + object->SetAlignedPointerInInternalField(index, value) +#define MATE_GET_INTERNAL_FIELD_POINTER(object, index) \ + object->GetAlignedPointerFromInternalField(index) + +#define MATE_PERSISTENT_INIT(isolate, handle, value) \ + handle(isolate, value) +#define MATE_PERSISTENT_ASSIGN(type, isolate, handle, value) \ + handle.Reset(isolate, value) +#define MATE_PERSISTENT_RESET(handle) \ + handle.Reset() +#define MATE_PERSISTENT_TO_LOCAL(type, isolate, handle) \ + v8::Local::New(isolate, handle) +#define MATE_PERSISTENT_SET_WEAK(handle, parameter, callback) \ + handle.SetWeak(parameter, callback) + +#define MATE_WEAK_CALLBACK(name, v8_type, c_type) \ + void name(const v8::WeakCallbackData& data) +#define MATE_WEAK_CALLBACK_INIT(c_type) \ + c_type* self = data.GetParameter() + +#else // Node 0.8 and 0.10 + +#define MATE_HANDLE_SCOPE(isolate) v8::HandleScope handle_scope + +#define MATE_METHOD_ARGS_TYPE v8::Arguments +#define MATE_METHOD_RETURN_TYPE v8::Handle + +#define MATE_METHOD_RETURN_VALUE(value) return value +#define MATE_METHOD_RETURN_UNDEFINED() return v8::Undefined() +#define MATE_METHOD_RETURN_NULL() return v8::Null() +#define MATE_METHOD_RETURN(value) \ + MATE_METHOD_RETURN_VALUE(ConvertToV8(args.isolate(), value)) + +#define MATE_STRING_NEW_FROM_UTF8(isolate, data, length) \ + v8::String::New(data, length) +#define MATE_STRING_NEW_SYMBOL(isolate, data, length) \ + v8::String::NewSymbol(data, length) + +#define MATE_SET_INTERNAL_FIELD_POINTER(object, index, value) \ + object->SetPointerInInternalField(index, value) +#define MATE_GET_INTERNAL_FIELD_POINTER(object, index) \ + object->GetPointerFromInternalField(index) + +#define MATE_PERSISTENT_INIT(isolate, handle, value) \ + handle(value) +#define MATE_PERSISTENT_ASSIGN(type, isolate, handle, value) \ + handle = v8::Persistent::New(value) +#define MATE_PERSISTENT_RESET(handle) \ + handle.Dispose(); \ + handle.Clear() +#define MATE_PERSISTENT_TO_LOCAL(type, isolate, handle) \ + v8::Local::New(handle) +#define MATE_PERSISTENT_SET_WEAK(handle, parameter, callback) \ + handle.MakeWeak(parameter, callback) + +#define MATE_WEAK_CALLBACK(name, v8_type, c_type) \ + void name(v8::Persistent object, void* parameter) +#define MATE_WEAK_CALLBACK_INIT(c_type) \ + c_type* self = static_cast(parameter) + +#endif // (NODE_MODULE_VERSION > 0x000B) + + +// Generally we should not provide utility macros, but this just makes things +// much more comfortable so we keep it. +#define MATE_METHOD(name) \ + MATE_METHOD_RETURN_TYPE name(const MATE_METHOD_ARGS_TYPE& info) + +// In lastest V8 ThrowException would need to pass isolate, be prepared for it. +#define MATE_THROW_EXCEPTION(isolate, value) \ + v8::ThrowException(value) + +#endif // NATIVE_MATE_COMPAT_H_ diff --git a/native_mate/converter.cc b/native_mate/converter.cc new file mode 100644 index 000000000000..4750e5a30a1d --- /dev/null +++ b/native_mate/converter.cc @@ -0,0 +1,190 @@ +// 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. + +#include "native_mate/converter.h" + +#include "native_mate/compat.h" +#include "v8/include/v8.h" + +using v8::Boolean; +using v8::External; +using v8::Function; +using v8::Handle; +using v8::Integer; +using v8::Isolate; +using v8::Number; +using v8::Object; +using v8::String; +using v8::Value; + +namespace mate { + +Handle Converter::ToV8(Isolate* isolate, bool val) { + return Boolean::New(val); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, bool* out) { + *out = val->BooleanValue(); + return true; +} + +Handle Converter::ToV8(Isolate* isolate, int32_t val) { + return Integer::New(val); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + int32_t* out) { + if (!val->IsInt32()) + return false; + *out = val->Int32Value(); + return true; +} + +Handle Converter::ToV8(Isolate* isolate, uint32_t val) { + return Integer::NewFromUnsigned(val); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + uint32_t* out) { + if (!val->IsUint32()) + return false; + *out = val->Uint32Value(); + return true; +} + +Handle Converter::ToV8(Isolate* isolate, int64_t val) { + return Number::New(static_cast(val)); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + int64_t* out) { + if (!val->IsNumber()) + return false; + // Even though IntegerValue returns int64_t, JavaScript cannot represent + // the full precision of int64_t, which means some rounding might occur. + *out = val->IntegerValue(); + return true; +} + +Handle Converter::ToV8(Isolate* isolate, uint64_t val) { + return Number::New(static_cast(val)); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + uint64_t* out) { + if (!val->IsNumber()) + return false; + *out = static_cast(val->IntegerValue()); + return true; +} + +Handle Converter::ToV8(Isolate* isolate, float val) { + return Number::New(val); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + float* out) { + if (!val->IsNumber()) + return false; + *out = static_cast(val->NumberValue()); + return true; +} + +Handle Converter::ToV8(Isolate* isolate, double val) { + return Number::New(val); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + double* out) { + if (!val->IsNumber()) + return false; + *out = val->NumberValue(); + return true; +} + +Handle Converter::ToV8( + Isolate* isolate, const base::StringPiece& val) { + return MATE_STRING_NEW_FROM_UTF8(isolate, val.data(), + static_cast(val.length())); +} + +Handle Converter::ToV8(Isolate* isolate, + const std::string& val) { + return Converter::ToV8(isolate, val); +} + +bool Converter::FromV8(Isolate* isolate, Handle val, + std::string* out) { + if (!val->IsString()) + return false; + Handle str = Handle::Cast(val); + int length = str->Utf8Length(); + out->resize(length); + str->WriteUtf8(&(*out)[0], length, NULL, String::NO_NULL_TERMINATION); + return true; +} + +bool Converter >::FromV8(Isolate* isolate, Handle val, + Handle* out) { + if (!val->IsFunction()) + return false; + *out = Handle::Cast(val); + return true; +} + +Handle Converter >::ToV8(Isolate* isolate, + Handle val) { + return val; +} + +bool Converter >::FromV8(Isolate* isolate, Handle val, + Handle* out) { + if (!val->IsObject()) + return false; + *out = Handle::Cast(val); + return true; +} + +Handle Converter >::ToV8(Isolate* isolate, + Handle val) { + return val; +} + +bool Converter >::FromV8(Isolate* isolate, + v8::Handle val, + Handle* out) { + if (!val->IsExternal()) + return false; + *out = Handle::Cast(val); + return true; +} + +Handle Converter >::ToV8(Isolate* isolate, + Handle val) { + return val; +} + +bool Converter >::FromV8(Isolate* isolate, Handle val, + Handle* out) { + *out = val; + return true; +} + +v8::Handle StringToSymbol(v8::Isolate* isolate, + const base::StringPiece& val) { + return MATE_STRING_NEW_SYMBOL(isolate, + val.data(), + static_cast(val.length())); +} + +std::string V8ToString(v8::Handle value) { + if (value.IsEmpty()) + return std::string(); + std::string result; + if (!ConvertFromV8(NULL, value, &result)) + return std::string(); + return result; +} + +} // namespace mate diff --git a/native_mate/converter.h b/native_mate/converter.h new file mode 100644 index 000000000000..44b7d4a882bd --- /dev/null +++ b/native_mate/converter.h @@ -0,0 +1,193 @@ +// 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. + +#ifndef NATIVE_MATE_CONVERTER_H_ +#define NATIVE_MATE_CONVERTER_H_ + +#include +#include + +#include "base/strings/string_piece.h" +#include "v8/include/v8.h" + +namespace mate { + +template +struct Converter {}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + bool val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + bool* out); +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + int32_t val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + int32_t* out); +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + uint32_t val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + uint32_t* out); +}; + +template<> +struct Converter { + // Warning: JavaScript cannot represent 64 integers precisely. + static v8::Handle ToV8(v8::Isolate* isolate, + int64_t val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + int64_t* out); +}; + +template<> +struct Converter { + // Warning: JavaScript cannot represent 64 integers precisely. + static v8::Handle ToV8(v8::Isolate* isolate, + uint64_t val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + uint64_t* out); +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + float val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + float* out); +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + double val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + double* out); +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + const base::StringPiece& val); + // No conversion out is possible because StringPiece does not contain storage. +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + const std::string& val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + std::string* out); +}; + +template<> +struct Converter > { + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + v8::Handle* out); +}; + +template<> +struct Converter > { + static v8::Handle ToV8(v8::Isolate* isolate, + v8::Handle val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + v8::Handle* out); +}; + +template<> +struct Converter > { + static v8::Handle ToV8(v8::Isolate* isolate, + v8::Handle val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + v8::Handle* out); +}; + +template<> +struct Converter > { + static v8::Handle ToV8(v8::Isolate* isolate, + v8::Handle val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + v8::Handle* out); +}; + +template +struct Converter > { + static v8::Handle ToV8(v8::Isolate* isolate, + const std::vector& val) { + v8::Handle result( + v8::Array::New(static_cast(val.size()))); + for (size_t i = 0; i < val.size(); ++i) { + result->Set(static_cast(i), Converter::ToV8(isolate, val[i])); + } + return result; + } + + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + std::vector* out) { + if (!val->IsArray()) + return false; + + std::vector result; + v8::Handle array(v8::Handle::Cast(val)); + uint32_t length = array->Length(); + for (uint32_t i = 0; i < length; ++i) { + T item; + if (!Converter::FromV8(isolate, array->Get(i), &item)) + return false; + result.push_back(item); + } + + out->swap(result); + return true; + } +}; + +// Convenience functions that deduce T. +template +v8::Handle ConvertToV8(v8::Isolate* isolate, + T input) { + return Converter::ToV8(isolate, input); +} + +inline v8::Handle StringToV8( + v8::Isolate* isolate, + const base::StringPiece& input) { + return ConvertToV8(isolate, input).As(); +} + +v8::Handle StringToSymbol(v8::Isolate* isolate, + const base::StringPiece& val); + +template +bool ConvertFromV8(v8::Isolate* isolate, v8::Handle input, + T* result) { + return Converter::FromV8(isolate, input, result); +} + +std::string V8ToString(v8::Handle value); + +} // namespace mate + +#endif // NATIVE_MATE_CONVERTER_H_ diff --git a/native_mate/dictionary.cc b/native_mate/dictionary.cc new file mode 100644 index 000000000000..1504f683f0a7 --- /dev/null +++ b/native_mate/dictionary.cc @@ -0,0 +1,42 @@ +// 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. + +#include "native_mate/dictionary.h" + +namespace mate { + +Dictionary::Dictionary(v8::Isolate* isolate) + : isolate_(isolate) { +} + +Dictionary::Dictionary(v8::Isolate* isolate, + v8::Handle object) + : isolate_(isolate), + object_(object) { +} + +Dictionary::~Dictionary() { +} + +Dictionary Dictionary::CreateEmpty(v8::Isolate* isolate) { + Dictionary dictionary(isolate); + dictionary.object_ = v8::Object::New(); + return dictionary; +} + +v8::Handle Converter::ToV8(v8::Isolate* isolate, + Dictionary val) { + return val.object_; +} + +bool Converter::FromV8(v8::Isolate* isolate, + v8::Handle val, + Dictionary* out) { + if (!val->IsObject()) + return false; + *out = Dictionary(isolate, v8::Handle::Cast(val)); + return true; +} + +} // namespace mate diff --git a/native_mate/dictionary.h b/native_mate/dictionary.h new file mode 100644 index 000000000000..469746653f40 --- /dev/null +++ b/native_mate/dictionary.h @@ -0,0 +1,64 @@ +// 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. + +#ifndef NATIVE_MATE_DICTIONARY_H_ +#define NATIVE_MATE_DICTIONARY_H_ + +#include "native_mate/converter.h" + +namespace mate { + +// Dictionary is useful when writing bindings for a function that either +// receives an arbitrary JavaScript object as an argument or returns an +// arbitrary JavaScript object as a result. For example, Dictionary is useful +// when you might use the |dictionary| type in WebIDL: +// +// http://heycam.github.io/webidl/#idl-dictionaries +// +// WARNING: You cannot retain a Dictionary object in the heap. The underlying +// storage for Dictionary is tied to the closest enclosing +// v8::HandleScope. Generally speaking, you should store a Dictionary +// on the stack. +// +class Dictionary { + public: + explicit Dictionary(v8::Isolate* isolate); + Dictionary(v8::Isolate* isolate, v8::Handle object); + ~Dictionary(); + + static Dictionary CreateEmpty(v8::Isolate* isolate); + + template + bool Get(const std::string& key, T* out) { + v8::Handle val = object_->Get(StringToV8(isolate_, key)); + return ConvertFromV8(isolate_, val, out); + } + + template + bool Set(const std::string& key, T val) { + return object_->Set(StringToV8(isolate_, key), ConvertToV8(isolate_, val)); + } + + v8::Isolate* isolate() const { return isolate_; } + + private: + friend struct Converter; + + // TODO(aa): Remove this. Instead, get via FromV8(), Set(), and Get(). + v8::Isolate* isolate_; + v8::Handle object_; +}; + +template<> +struct Converter { + static v8::Handle ToV8(v8::Isolate* isolate, + Dictionary val); + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + Dictionary* out); +}; + +} // namespace mate + +#endif // NATIVE_MATE_DICTIONARY_H_ diff --git a/native_mate/function_template.cc b/native_mate/function_template.cc new file mode 100644 index 000000000000..711c04150a40 --- /dev/null +++ b/native_mate/function_template.cc @@ -0,0 +1,35 @@ +// 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. + +#include "native_mate/function_template.h" + +namespace mate { + +namespace internal { + +CallbackHolderBase::CallbackHolderBase(v8::Isolate* isolate) + : MATE_PERSISTENT_INIT(isolate, v8_ref_, v8::External::New(isolate)) { + MATE_PERSISTENT_SET_WEAK(v8_ref_, this, &CallbackHolderBase::WeakCallback); +} + +CallbackHolderBase::~CallbackHolderBase() { + DCHECK(v8_ref_.IsEmpty()); +} + +v8::Handle CallbackHolderBase::GetHandle(v8::Isolate* isolate) { + return MATE_PERSISTENT_TO_LOCAL(v8::External, isolate, v8_ref_); +} + +// static +MATE_WEAK_CALLBACK(CallbackHolderBase::WeakCallback, + v8::External, + CallbackHolderBase) { + MATE_WEAK_CALLBACK_INIT(CallbackHolderBase); + MATE_PERSISTENT_RESET(self->v8_ref_); + delete self; +} + +} // namespace internal + +} // namespace mate diff --git a/native_mate/function_template.h b/native_mate/function_template.h new file mode 100644 index 000000000000..2dd5ba5cc4f9 --- /dev/null +++ b/native_mate/function_template.h @@ -0,0 +1,498 @@ +// 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. + +#ifndef NATIVE_MATE_FUNCTION_TEMPLATE_H_ +#define NATIVE_MATE_FUNCTION_TEMPLATE_H_ + +#include "base/callback.h" +#include "base/logging.h" +#include "native_mate/arguments.h" +#include "native_mate/converter.h" +#include "v8/include/v8.h" + +namespace mate { + +class PerIsolateData; + +enum CreateFunctionTemplateFlags { + HolderIsFirstArgument = 1 << 0, +}; + +namespace internal { + +template +struct CallbackParamTraits { + typedef T LocalType; +}; +template +struct CallbackParamTraits { + typedef T LocalType; +}; +template +struct CallbackParamTraits { + typedef T* LocalType; +}; + + +// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from +// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to +// DispatchToCallback, where it is invoked. + +// This simple base class is used so that we can share a single object template +// among every CallbackHolder instance. +class CallbackHolderBase { + public: + v8::Handle GetHandle(v8::Isolate* isolate); + + protected: + explicit CallbackHolderBase(v8::Isolate* isolate); + virtual ~CallbackHolderBase(); + + private: + static MATE_WEAK_CALLBACK(WeakCallback, v8::External, CallbackHolderBase); + + v8::Persistent v8_ref_; + + DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase); +}; + +template +class CallbackHolder : public CallbackHolderBase { + public: + CallbackHolder(v8::Isolate* isolate, + const base::Callback& callback, + int flags) + : CallbackHolderBase(isolate), callback(callback), flags(flags) {} + base::Callback callback; + int flags; + private: + virtual ~CallbackHolder() {} + + DISALLOW_COPY_AND_ASSIGN(CallbackHolder); +}; + + +// This set of templates invokes a base::Callback, converts the return type to a +// JavaScript value, and returns that value to script via the provided +// mate::Arguments object. +// +// In C++, you can declare the function foo(void), but you can't pass a void +// expression to foo. As a result, we must specialize the case of Callbacks that +// have the void return type. +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3, + const P4& a4, + const P5& a5, + const P6& a6) { + MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5, a6)); + } +}; +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3, + const P4& a4, + const P5& a5, + const P6& a6) { + callback.Run(a1, a2, a3, a4, a5, a6); + MATE_METHOD_RETURN_UNDEFINED(); + } +}; + +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3, + const P4& a4, + const P5& a5) { + MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4, a5)); + } +}; +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3, + const P4& a4, + const P5& a5) { + callback.Run(a1, a2, a3, a4, a5); + MATE_METHOD_RETURN_UNDEFINED(); + } +}; + +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3, + const P4& a4) { + MATE_METHOD_RETURN(callback.Run(a1, a2, a3, a4)); + } +}; +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3, + const P4& a4) { + callback.Run(a1, a2, a3, a4); + MATE_METHOD_RETURN_UNDEFINED(); + } +}; + +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3) { + MATE_METHOD_RETURN(callback.Run(a1, a2, a3)); + } +}; +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2, + const P3& a3) { + callback.Run(a1, a2, a3); + MATE_METHOD_RETURN_UNDEFINED(); + } +}; + +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2) { + MATE_METHOD_RETURN(callback.Run(a1, a2)); + } +}; +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1, + const P2& a2) { + callback.Run(a1, a2); + MATE_METHOD_RETURN_UNDEFINED(); + } +}; + +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1) { + MATE_METHOD_RETURN(callback.Run(a1)); + } +}; +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback, + const P1& a1) { + MATE_METHOD_RETURN(callback.Run(a1)); + } +}; + +template +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback) { + MATE_METHOD_RETURN(callback.Run()); + } +}; +template<> +struct Invoker { + inline static MATE_METHOD_RETURN_TYPE Go( + Arguments& args, + const base::Callback& callback) { + callback.Run(); + MATE_METHOD_RETURN_UNDEFINED(); + } +}; + + +template +bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + T* result) { + if (is_first && (create_flags & HolderIsFirstArgument) != 0) { + return args->GetHolder(result); + } else { + return args->GetNext(result); + } +} + +// For advanced use cases, we allow callers to request the unparsed Arguments +// object and poke around in it directly. +inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + Arguments* result) { + *result = *args; + return true; +} +inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + Arguments** result) { + *result = args; + return true; +} + +// It's common for clients to just need the isolate, so we make that easy. +inline bool GetNextArgument(Arguments* args, int create_flags, + bool is_first, v8::Isolate** result) { + *result = args->isolate(); + return true; +} + + +// DispatchToCallback converts all the JavaScript arguments to C++ types and +// invokes the base::Callback. +template +struct Dispatcher { +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + return Invoker::Go(args, holder->callback); + } +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + typename CallbackParamTraits::LocalType a1; + if (!GetNextArgument(args, holder->flags, true, &a1)) { + args.ThrowError(); + MATE_METHOD_RETURN_UNDEFINED(); + } + + return Invoker::Go(args, holder->callback, a1); + } +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + if (!GetNextArgument(args, holder->flags, true, &a1) || + !GetNextArgument(args, holder->flags, false, &a2)) { + args.ThrowError(); + MATE_METHOD_RETURN_UNDEFINED(); + } + + return Invoker::Go(args, holder->callback, a1, a2); + } +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + if (!GetNextArgument(args, holder->flags, true, &a1) || + !GetNextArgument(args, holder->flags, false, &a2) || + !GetNextArgument(args, holder->flags, false, &a3)) { + args.ThrowError(); + MATE_METHOD_RETURN_UNDEFINED(); + } + + return Invoker::Go(args, holder->callback, a1, a2, a3); + } +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + typename CallbackParamTraits::LocalType a4; + if (!GetNextArgument(args, holder->flags, true, &a1) || + !GetNextArgument(args, holder->flags, false, &a2) || + !GetNextArgument(args, holder->flags, false, &a3) || + !GetNextArgument(args, holder->flags, false, &a4)) { + args.ThrowError(); + MATE_METHOD_RETURN_UNDEFINED(); + } + + return Invoker::Go(args, holder->callback, a1, a2, a3, + a4); + } +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + typename CallbackParamTraits::LocalType a4; + typename CallbackParamTraits::LocalType a5; + if (!GetNextArgument(args, holder->flags, true, &a1) || + !GetNextArgument(args, holder->flags, false, &a2) || + !GetNextArgument(args, holder->flags, false, &a3) || + !GetNextArgument(args, holder->flags, false, &a4) || + !GetNextArgument(args, holder->flags, false, &a5)) { + args.ThrowError(); + MATE_METHOD_RETURN_UNDEFINED(); + } + + return Invoker::Go(args, holder->callback, a1, a2, + a3, a4, a5); + } +}; + +template +struct Dispatcher { + static MATE_METHOD(DispatchToCallback) { + Arguments args(info); + v8::Handle v8_holder; + CHECK(args.GetData(&v8_holder)); + CallbackHolderBase* holder_base = reinterpret_cast( + v8_holder->Value()); + + typedef CallbackHolder HolderT; + HolderT* holder = static_cast(holder_base); + + typename CallbackParamTraits::LocalType a1; + typename CallbackParamTraits::LocalType a2; + typename CallbackParamTraits::LocalType a3; + typename CallbackParamTraits::LocalType a4; + typename CallbackParamTraits::LocalType a5; + typename CallbackParamTraits::LocalType a6; + if (!GetNextArgument(args, holder->flags, true, &a1) || + !GetNextArgument(args, holder->flags, false, &a2) || + !GetNextArgument(args, holder->flags, false, &a3) || + !GetNextArgument(args, holder->flags, false, &a4) || + !GetNextArgument(args, holder->flags, false, &a5) || + !GetNextArgument(args, holder->flags, false, &a6)) { + args.ThrowError(); + MATE_METHOD_RETURN_UNDEFINED(); + } + + return Invoker::Go(args, holder->callback, a1, + a2, a3, a4, a5, a6); + } +}; + +} // namespace internal + + +// CreateFunctionTemplate creates a v8::FunctionTemplate that will create +// JavaScript functions that execute a provided C++ function or base::Callback. +// JavaScript arguments are automatically converted via mate::Converter, as is +// the return value of the C++ function, if any. +template +v8::Local CreateFunctionTemplate( + v8::Isolate* isolate, const base::Callback callback, + int callback_flags = 0) { + typedef internal::CallbackHolder HolderT; + HolderT* holder = new HolderT(isolate, callback, callback_flags); + + return v8::FunctionTemplate::New( + isolate, + &internal::Dispatcher::DispatchToCallback, + ConvertToV8 >(isolate, + holder->GetHandle(isolate))); +} + +} // namespace mate + +#endif // NATIVE_MATE_FUNCTION_TEMPLATE_H_ diff --git a/native_mate/handle.h b/native_mate/handle.h new file mode 100644 index 000000000000..f81b9d12509b --- /dev/null +++ b/native_mate/handle.h @@ -0,0 +1,68 @@ +// 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. + +#ifndef NATIVE_MATE_HANDLE_H_ +#define NATIVE_MATE_HANDLE_H_ + +#include "native_mate/converter.h" + +namespace mate { + +// You can use mate::Handle on the stack to retain a mate::Wrappable object. +// Currently we don't have a mechanism for retaining a mate::Wrappable object +// in the C++ heap because strong references from C++ to V8 can cause memory +// leaks. +template +class Handle { + public: + Handle() : object_(NULL) {} + + Handle(v8::Handle wrapper, T* object) + : wrapper_(wrapper), + object_(object) { + } + + bool IsEmpty() const { return !object_; } + + void Clear() { + wrapper_.Clear(); + object_ = NULL; + } + + T* operator->() const { return object_; } + v8::Handle ToV8() const { return wrapper_; } + T* get() const { return object_; } + + private: + v8::Handle wrapper_; + T* object_; +}; + +template +struct Converter > { + static v8::Handle ToV8(v8::Isolate* isolate, + const mate::Handle& val) { + return val.ToV8(); + } + static bool FromV8(v8::Isolate* isolate, v8::Handle val, + mate::Handle* out) { + T* object = NULL; + if (!Converter::FromV8(isolate, val, &object)) { + return false; + } + *out = mate::Handle(val, object); + return true; + } +}; + +// This function is a convenient way to create a handle from a raw pointer +// without having to write out the type of the object explicitly. +template +mate::Handle CreateHandle(v8::Isolate* isolate, T* object) { + return mate::Handle(object->GetWrapper(isolate), object); +} + +} // namespace mate + +#endif // NATIVE_MATE_HANDLE_H_ diff --git a/native_mate/object_template_builder.cc b/native_mate/object_template_builder.cc new file mode 100644 index 000000000000..a8022158fb67 --- /dev/null +++ b/native_mate/object_template_builder.cc @@ -0,0 +1,39 @@ +// 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. + +#include "native_mate/object_template_builder.h" + +namespace mate { + +ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate) + : isolate_(isolate), template_(v8::ObjectTemplate::New()) { + template_->SetInternalFieldCount(1); +} + +ObjectTemplateBuilder::~ObjectTemplateBuilder() { +} + +ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl( + const base::StringPiece& name, v8::Handle val) { + template_->Set(StringToSymbol(isolate_, name), val); + return *this; +} + +ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl( + const base::StringPiece& name, v8::Handle getter, + v8::Handle setter) { +#if NODE_VERSION_AT_LEAST(0, 11, 0) + template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter, + setter); +#endif + return *this; +} + +v8::Local ObjectTemplateBuilder::Build() { + v8::Local result = template_; + template_.Clear(); + return result; +} + +} // namespace mate diff --git a/native_mate/object_template_builder.h b/native_mate/object_template_builder.h new file mode 100644 index 000000000000..a0fad1569b51 --- /dev/null +++ b/native_mate/object_template_builder.h @@ -0,0 +1,123 @@ +// 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. + +#ifndef NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_ +#define NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_ + +#include "base/bind.h" +#include "base/callback.h" +#include "base/strings/string_piece.h" +#include "base/template_util.h" +#include "native_mate/converter.h" +#include "native_mate/function_template.h" +#include "v8/include/v8.h" + +namespace mate { + +namespace { + +// Base template - used only for non-member function pointers. Other types +// either go to one of the below specializations, or go here and fail to compile +// because of base::Bind(). +template +struct CallbackTraits { + static v8::Handle CreateTemplate(v8::Isolate* isolate, + T callback) { + return CreateFunctionTemplate(isolate, base::Bind(callback)); + } +}; + +// Specialization for base::Callback. +template +struct CallbackTraits > { + static v8::Handle CreateTemplate( + v8::Isolate* isolate, const base::Callback& callback) { + return CreateFunctionTemplate(isolate, callback); + } +}; + +// Specialization for member function pointers. We need to handle this case +// specially because the first parameter for callbacks to MFP should typically +// come from the the JavaScript "this" object the function was called on, not +// from the first normal parameter. +template +struct CallbackTraits::value>::type> { + static v8::Handle CreateTemplate(v8::Isolate* isolate, + T callback) { + return CreateFunctionTemplate(isolate, base::Bind(callback), + HolderIsFirstArgument); + } +}; + +// This specialization allows people to construct function templates directly if +// they need to do fancier stuff. +template<> +struct CallbackTraits > { + static v8::Handle CreateTemplate( + v8::Handle templ) { + return templ; + } +}; + +} // namespace + + +// ObjectTemplateBuilder provides a handy interface to creating +// v8::ObjectTemplate instances with various sorts of properties. +class ObjectTemplateBuilder { + public: + explicit ObjectTemplateBuilder(v8::Isolate* isolate); + ~ObjectTemplateBuilder(); + + // It's against Google C++ style to return a non-const ref, but we take some + // poetic license here in order that all calls to Set() can be via the '.' + // operator and line up nicely. + template + ObjectTemplateBuilder& SetValue(const base::StringPiece& name, T val) { + return SetImpl(name, ConvertToV8(isolate_, val)); + } + + // In the following methods, T and U can be function pointer, member function + // pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to + // use one of the first two options. Also see mate::CreateFunctionTemplate() + // for creating raw function templates. + template + ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, + const T& callback) { + return SetImpl(name, CallbackTraits::CreateTemplate(isolate_, callback)); + } + template + ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, + const T& getter) { + return SetPropertyImpl(name, + CallbackTraits::CreateTemplate(isolate_, getter), + v8::Local()); + } + template + ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, + const T& getter, const U& setter) { + return SetPropertyImpl(name, + CallbackTraits::CreateTemplate(isolate_, getter), + CallbackTraits::CreateTemplate(isolate_, setter)); + } + + v8::Local Build(); + + private: + ObjectTemplateBuilder& SetImpl(const base::StringPiece& name, + v8::Handle val); + ObjectTemplateBuilder& SetPropertyImpl( + const base::StringPiece& name, v8::Handle getter, + v8::Handle setter); + + v8::Isolate* isolate_; + + // ObjectTemplateBuilder should only be used on the stack. + v8::Local template_; +}; + +} // namespace mate + +#endif // NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_ diff --git a/native_mate/scoped_persistent.h b/native_mate/scoped_persistent.h new file mode 100644 index 000000000000..c1705676c282 --- /dev/null +++ b/native_mate/scoped_persistent.h @@ -0,0 +1,111 @@ +// Copyright 2014 Cheng Zhao. All rights reserved. +// Use of this source code is governed by MIT license that can be found in the +// LICENSE file. + +#ifndef NATIVE_MATE_SCOPED_PERSISTENT_H_ +#define NATIVE_MATE_SCOPED_PERSISTENT_H_ + +#include "base/memory/ref_counted.h" +#include "v8/include/v8.h" + +namespace mate { + +// A v8::Persistent handle to a V8 value which destroys and clears the +// underlying handle on destruction. +template +class ScopedPersistent { + public: + ScopedPersistent() { + } + + explicit ScopedPersistent(v8::Handle handle) { + reset(handle); + } + + ~ScopedPersistent() { + reset(); + } + + void reset(v8::Handle handle) { + if (!handle.IsEmpty()) + handle_.Reset(GetIsolate(handle), handle); + else + reset(); + } + + void reset() { + handle_.Reset(); + } + + bool IsEmpty() const { + return handle_.IsEmpty(); + } + + v8::Handle NewHandle() const { + if (handle_.IsEmpty()) + return v8::Local(); + return v8::Local::New(GetIsolate(handle_), handle_); + } + + v8::Handle NewHandle(v8::Isolate* isolate) const { + if (handle_.IsEmpty()) + return v8::Local(); + return v8::Local::New(isolate, handle_); + } + + template + void MakeWeak(P* parameters, + typename v8::WeakReferenceCallbacks::Revivable callback) { + handle_.MakeWeak(parameters, callback); + } + + private: + template + static v8::Isolate* GetIsolate(v8::Handle object_handle) { + // Only works for v8::Object and its subclasses. Add specialisations for + // anything else. + if (!object_handle.IsEmpty()) + return GetIsolate(object_handle->CreationContext()); + return v8::Isolate::GetCurrent(); + } + static v8::Isolate* GetIsolate(v8::Handle context_handle) { + if (!context_handle.IsEmpty()) + return context_handle->GetIsolate(); + return v8::Isolate::GetCurrent(); + } + static v8::Isolate* GetIsolate( + v8::Handle template_handle) { + return v8::Isolate::GetCurrent(); + } + template + static v8::Isolate* GetIsolate(const U& any_handle) { + return v8::Isolate::GetCurrent(); + } + + v8::Persistent handle_; + + DISALLOW_COPY_AND_ASSIGN(ScopedPersistent); +}; + +template +class RefCountedPersistent : public ScopedPersistent, + public base::RefCounted> { + public: + RefCountedPersistent() {} + + explicit RefCountedPersistent(v8::Handle handle) + : ScopedPersistent(handle) { + } + + protected: + friend class base::RefCounted>; + + ~RefCountedPersistent() {} + + private: + DISALLOW_COPY_AND_ASSIGN(RefCountedPersistent); +}; + +} // namespace mate + +#endif // NATIVE_MATE_SCOPED_PERSISTENT_H_ diff --git a/native_mate/try_catch.cc b/native_mate/try_catch.cc new file mode 100644 index 000000000000..c3efd3cddd4a --- /dev/null +++ b/native_mate/try_catch.cc @@ -0,0 +1,49 @@ +// 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. + +#include "native_mate/try_catch.h" + +#include + +#include "native_mate/converter.h" + +namespace mate { + +TryCatch::TryCatch() { +} + +TryCatch::~TryCatch() { +} + +bool TryCatch::HasCaught() { + return try_catch_.HasCaught(); +} + +std::string TryCatch::GetStackTrace() { + if (!HasCaught()) { + return ""; + } + + std::stringstream ss; + v8::Handle message = try_catch_.Message(); + ss << V8ToString(message->Get()) << std::endl + << V8ToString(message->GetSourceLine()) << std::endl; + + v8::Handle trace = message->GetStackTrace(); + if (trace.IsEmpty()) + return ss.str(); + + int len = trace->GetFrameCount(); + for (int i = 0; i < len; ++i) { + v8::Handle frame = trace->GetFrame(i); + ss << V8ToString(frame->GetScriptName()) << ":" + << frame->GetLineNumber() << ":" + << frame->GetColumn() << ": " + << V8ToString(frame->GetFunctionName()) + << std::endl; + } + return ss.str(); +} + +} // namespace mate diff --git a/native_mate/try_catch.h b/native_mate/try_catch.h new file mode 100644 index 000000000000..3b3ece873605 --- /dev/null +++ b/native_mate/try_catch.h @@ -0,0 +1,32 @@ +// 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. + +#ifndef NATIVE_MATE_TRY_CATCH_H_ +#define NATIVE_MATE_TRY_CATCH_H_ + +#include + +#include "base/basictypes.h" +#include "v8/include/v8.h" + +namespace mate { + +// TryCatch is a convenient wrapper around v8::TryCatch. +class TryCatch { + public: + TryCatch(); + ~TryCatch(); + + bool HasCaught(); + std::string GetStackTrace(); + + private: + v8::TryCatch try_catch_; + + DISALLOW_COPY_AND_ASSIGN(TryCatch); +}; + +} // namespace mate + +#endif // NATIVE_MATE_TRY_CATCH_H_ diff --git a/native_mate/wrappable.cc b/native_mate/wrappable.cc new file mode 100644 index 000000000000..77bd721ad2f8 --- /dev/null +++ b/native_mate/wrappable.cc @@ -0,0 +1,58 @@ +// 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. + +#include "native_mate/wrappable.h" + +#include "base/logging.h" +#include "native_mate/object_template_builder.h" + +namespace mate { + +Wrappable::Wrappable() { +} + +Wrappable::~Wrappable() { + MATE_PERSISTENT_RESET(wrapper_); +} + +ObjectTemplateBuilder Wrappable::GetObjectTemplateBuilder( + v8::Isolate* isolate) { + return ObjectTemplateBuilder(isolate); +} + +// static +MATE_WEAK_CALLBACK(Wrappable::WeakCallback, v8::Object, Wrappable) { + MATE_WEAK_CALLBACK_INIT(Wrappable); + MATE_PERSISTENT_RESET(self->wrapper_); + delete self; +} + +v8::Handle Wrappable::GetWrapper(v8::Isolate* isolate) { + if (!wrapper_.IsEmpty()) { + return MATE_PERSISTENT_TO_LOCAL(v8::Object, isolate, wrapper_); + } + + v8::Local templ = + GetObjectTemplateBuilder(isolate).Build(); + CHECK(!templ.IsEmpty()); + CHECK_EQ(1, templ->InternalFieldCount()); + v8::Handle wrapper = templ->NewInstance(); + MATE_SET_INTERNAL_FIELD_POINTER(wrapper, 0, this); + MATE_PERSISTENT_ASSIGN(v8::Object, isolate, wrapper_, wrapper); + MATE_PERSISTENT_SET_WEAK(wrapper_, this, WeakCallback); + return wrapper; +} + +namespace internal { + +void* FromV8Impl(v8::Isolate* isolate, v8::Handle val) { + if (!val->IsObject()) + return NULL; + v8::Handle obj = v8::Handle::Cast(val); + return MATE_GET_INTERNAL_FIELD_POINTER(obj, 0); +} + +} // namespace internal + +} // namespace mate diff --git a/native_mate/wrappable.h b/native_mate/wrappable.h new file mode 100644 index 000000000000..949a9ebebd9b --- /dev/null +++ b/native_mate/wrappable.h @@ -0,0 +1,85 @@ +// 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. + +#ifndef NATIVE_MATE_WRAPPABLE_H_ +#define NATIVE_MATE_WRAPPABLE_H_ + +#include "base/template_util.h" +#include "native_mate/compat.h" +#include "native_mate/converter.h" + +namespace mate { + +namespace internal { + +void* FromV8Impl(v8::Isolate* isolate, v8::Handle val); + +} // namespace internal + + +// Wrappable is a base class for C++ objects that have corresponding v8 wrapper +// objects. To retain a Wrappable object on the stack, use a mate::Handle. +// +// USAGE: +// // my_class.h +// class MyClass : Wrappable { +// public: +// // Optional, only required if non-empty template should be used. +// virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( +// v8::Isolate* isolate); +// ... +// }; +// +// mate::ObjectTemplateBuilder MyClass::GetObjectTemplateBuilder( +// v8::Isolate* isolate) { +// return Wrappable::GetObjectTemplateBuilder(isolate).SetValue("foobar", 42); +// } +// +// Subclasses should also typically have private constructors and expose a +// static Create function that returns a mate::Handle. Forcing creators through +// this static Create function will enforce that clients actually create a +// wrapper for the object. If clients fail to create a wrapper for a wrappable +// object, the object will leak because we use the weak callback from the +// wrapper as the signal to delete the wrapped object. +class ObjectTemplateBuilder; + +// Non-template base class to share code between templates instances. +class Wrappable { + public: + // Retrieve (or create) the v8 wrapper object cooresponding to this object. + v8::Handle GetWrapper(v8::Isolate* isolate); + + protected: + Wrappable(); + virtual ~Wrappable(); + + virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate); + + private: + static MATE_WEAK_CALLBACK(WeakCallback, v8::Object, Wrappable); + + v8::Persistent wrapper_; // Weak + + DISALLOW_COPY_AND_ASSIGN(Wrappable); +}; + + +// This converter handles any subclass of Wrappable. +template +struct Converter::value>::type> { + static v8::Handle ToV8(v8::Isolate* isolate, T* val) { + return val->GetWrapper(isolate); + } + + static bool FromV8(v8::Isolate* isolate, v8::Handle val, T** out) { + *out = static_cast(static_cast( + internal::FromV8Impl(isolate, val))); + return *out != NULL; + } +}; + +} // namespace mate + +#endif // NATIVE_MATE_WRAPPABLE_H_ diff --git a/native_mate_files.gypi b/native_mate_files.gypi new file mode 100644 index 000000000000..1496ab4f91e3 --- /dev/null +++ b/native_mate_files.gypi @@ -0,0 +1,23 @@ +{ + 'variables': { + 'native_mate_files': [ + 'native_mate/arguments.cc', + 'native_mate/arguments.h', + 'native_mate/compat.h', + 'native_mate/converter.cc', + 'native_mate/converter.h', + 'native_mate/dictionary.cc', + 'native_mate/dictionary.h', + 'native_mate/function_template.cc', + 'native_mate/function_template.h', + 'native_mate/handle.h', + 'native_mate/object_template_builder.cc', + 'native_mate/object_template_builder.h', + 'native_mate/scoped_persistent.h', + 'native_mate/try_catch.cc', + 'native_mate/try_catch.h', + 'native_mate/wrappable.cc', + 'native_mate/wrappable.h', + ], + }, +}