diff --git a/engine/tonic/BUILD.gn b/engine/tonic/BUILD.gn new file mode 100644 index 00000000000..18c03c15e1c --- /dev/null +++ b/engine/tonic/BUILD.gn @@ -0,0 +1,49 @@ +# Copyright 2015 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. + +source_set("tonic") { + sources = [ + "dart_api_scope.h", + "dart_builtin.cc", + "dart_builtin.h", + "dart_class_library.cc", + "dart_class_library.h", + "dart_class_provider.cc", + "dart_class_provider.h", + "dart_converter.cc", + "dart_converter.h", + "dart_error.cc", + "dart_error.h", + "dart_gc_context.cc", + "dart_gc_context.h", + "dart_gc_controller.cc", + "dart_gc_controller.h", + "dart_gc_visitor.cc", + "dart_gc_visitor.h", + "dart_isolate_scope.cc", + "dart_isolate_scope.h", + "dart_persistent_value.cc", + "dart_persistent_value.h", + "dart_state.cc", + "dart_state.h", + "dart_string.cc", + "dart_string.h", + "dart_string_cache.cc", + "dart_string_cache.h", + "dart_value.cc", + "dart_value.h", + "dart_wrappable.cc", + "dart_wrappable.h", + "dart_wrapper_info.h", + ] + + deps = [ + "//base", + "//sky/engine/wtf", + ] + + public_deps = [ + "//dart/runtime/bin:libdart_withcore", + ] +} diff --git a/engine/tonic/dart_api_scope.h b/engine/tonic/dart_api_scope.h new file mode 100644 index 00000000000..9b4be391cbc --- /dev/null +++ b/engine/tonic/dart_api_scope.h @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_API_SCOPE_H_ +#define SKY_ENGINE_TONIC_DART_API_SCOPE_H_ + +#include "base/macros.h" +#include "dart/runtime/include/dart_api.h" + +namespace blink { + +class DartApiScope { + public: + DartApiScope() { Dart_EnterScope(); } + ~DartApiScope() { Dart_ExitScope(); } + + private: + DISALLOW_COPY_AND_ASSIGN(DartApiScope); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_API_SCOPE_H_ diff --git a/engine/tonic/dart_builtin.cc b/engine/tonic/dart_builtin.cc new file mode 100644 index 00000000000..9a8f5356ab7 --- /dev/null +++ b/engine/tonic/dart_builtin.cc @@ -0,0 +1,50 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_builtin.h" + +#include +#include + +#include "base/logging.h" + +namespace blink { + +DartBuiltin::DartBuiltin(const Natives* natives, size_t count) + : natives_(natives), count_(count) { +} + +DartBuiltin::~DartBuiltin() { +} + +Dart_NativeFunction DartBuiltin::Resolver(Dart_Handle name, + int argument_count, + bool* auto_setup_scope) const { + const char* function_name = nullptr; + Dart_Handle result = Dart_StringToCString(name, &function_name); + DART_CHECK_VALID(result); + DCHECK(function_name != nullptr); + DCHECK(auto_setup_scope != nullptr); + *auto_setup_scope = true; + for (size_t i = 0; i < count_; ++i) { + const Natives& entry = natives_[i]; + if (!strcmp(function_name, entry.name) && + (entry.argument_count == argument_count)) { + return entry.function; + } + } + return nullptr; +} + +const uint8_t* DartBuiltin::Symbolizer(Dart_NativeFunction native_function) const { + for (size_t i = 0; i < count_; ++i) { + const Natives& entry = natives_[i]; + if (entry.function == native_function) + return reinterpret_cast(entry.name); + } + return nullptr; +} + +} // namespace blink diff --git a/engine/tonic/dart_builtin.h b/engine/tonic/dart_builtin.h new file mode 100644 index 00000000000..ce0106f80f1 --- /dev/null +++ b/engine/tonic/dart_builtin.h @@ -0,0 +1,39 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_BUILTIN_H_ +#define SKY_ENGINE_TONIC_DART_BUILTIN_H_ + +#include "base/macros.h" +#include "dart/runtime/include/dart_api.h" + +namespace blink { + +class DartBuiltin { + public: + struct Natives { + const char* name; + Dart_NativeFunction function; + int argument_count; + }; + + DartBuiltin(const Natives* natives, size_t count); + ~DartBuiltin(); + + Dart_NativeFunction Resolver(Dart_Handle name, + int argument_count, + bool* auto_setup_scope) const; + + const uint8_t* Symbolizer(Dart_NativeFunction native_function) const; + + private: + const Natives* natives_; + size_t count_; + + DISALLOW_COPY_AND_ASSIGN(DartBuiltin); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_BUILTIN_H_ diff --git a/engine/tonic/dart_class_library.cc b/engine/tonic/dart_class_library.cc new file mode 100644 index 00000000000..dddcb236274 --- /dev/null +++ b/engine/tonic/dart_class_library.cc @@ -0,0 +1,34 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_class_library.h" + +#include "base/logging.h" +#include "sky/engine/tonic/dart_wrapper_info.h" + +namespace blink { + +DartClassLibrary::DartClassLibrary() : provider_(nullptr) { +} + +DartClassLibrary::~DartClassLibrary() { + // Note that we don't need to delete these persistent handles because this + // object lives as long as the isolate. The handles will get deleted when the + // isolate dies. +} + +Dart_PersistentHandle DartClassLibrary::GetClass(const DartWrapperInfo& info) { + DCHECK(provider_); + + const auto& result = cache_.add(&info, nullptr); + if (!result.isNewEntry) + return result.storedValue->value; + + Dart_Handle class_handle = provider_->GetClassByName(info.interface_name); + result.storedValue->value = Dart_NewPersistentHandle(class_handle); + return result.storedValue->value; +} + +} // namespace blink diff --git a/engine/tonic/dart_class_library.h b/engine/tonic/dart_class_library.h new file mode 100644 index 00000000000..5a1b2125d86 --- /dev/null +++ b/engine/tonic/dart_class_library.h @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_CLASS_LIBRARY_H_ +#define SKY_ENGINE_TONIC_DART_CLASS_LIBRARY_H_ + +#include "base/macros.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/tonic/dart_class_provider.h" +#include "sky/engine/wtf/HashMap.h" + +namespace blink { +struct DartWrapperInfo; + +class DartClassLibrary { + public: + explicit DartClassLibrary(); + ~DartClassLibrary(); + + void set_provider(DartClassProvider* provider) { provider_ = provider; } + Dart_PersistentHandle GetClass(const DartWrapperInfo& info); + + private: + DartClassProvider* provider_; + HashMap cache_; + + DISALLOW_COPY_AND_ASSIGN(DartClassLibrary); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_CLASS_LIBRARY_H_ diff --git a/engine/tonic/dart_class_provider.cc b/engine/tonic/dart_class_provider.cc new file mode 100644 index 00000000000..70ce8541f3a --- /dev/null +++ b/engine/tonic/dart_class_provider.cc @@ -0,0 +1,13 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_class_provider.h" + +namespace blink { + +DartClassProvider::~DartClassProvider() { +} + +} // namespace blink diff --git a/engine/tonic/dart_class_provider.h b/engine/tonic/dart_class_provider.h new file mode 100644 index 00000000000..35b55ae26e3 --- /dev/null +++ b/engine/tonic/dart_class_provider.h @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_CLASS_PROVIDER_H_ +#define SKY_ENGINE_TONIC_DART_CLASS_PROVIDER_H_ + +#include "dart/runtime/include/dart_api.h" + +namespace blink { + +class DartClassProvider { + public: + virtual Dart_Handle GetClassByName(const char* class_name) = 0; + + protected: + virtual ~DartClassProvider(); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_CLASS_PROVIDER_H_ diff --git a/engine/tonic/dart_converter.cc b/engine/tonic/dart_converter.cc new file mode 100644 index 00000000000..3ba7a69afbd --- /dev/null +++ b/engine/tonic/dart_converter.cc @@ -0,0 +1,8 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_converter.h" + +// This file exists to ensure dart_converter.h doesn't miss any dependencies. diff --git a/engine/tonic/dart_converter.h b/engine/tonic/dart_converter.h new file mode 100644 index 00000000000..37b80d63542 --- /dev/null +++ b/engine/tonic/dart_converter.h @@ -0,0 +1,325 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_CONVERTER_H_ +#define SKY_ENGINE_TONIC_DART_CONVERTER_H_ + +#include +#include "sky/engine/tonic/dart_state.h" +#include "sky/engine/tonic/dart_string.h" +#include "sky/engine/tonic/dart_string_cache.h" +#include "sky/engine/tonic/dart_value.h" +#include "sky/engine/wtf/text/StringUTF8Adaptor.h" +#include "sky/engine/wtf/text/WTFString.h" + +namespace blink { + +// DartConvert converts types back and forth from Sky to Dart. The template +// parameter |T| determines what kind of type conversion to perform. +template +struct DartConverter {}; + +//////////////////////////////////////////////////////////////////////////////// +// Boolean + +template <> +struct DartConverter { + static Dart_Handle ToDart(bool val) { return Dart_NewBoolean(val); } + + static void SetReturnValue(Dart_NativeArguments args, bool val) { + Dart_SetBooleanReturnValue(args, val); + } + + static bool FromDart(Dart_Handle handle) { + bool result = 0; + Dart_BooleanValue(handle, &result); + return result; + } + + static bool FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception) { + bool result = false; + Dart_GetNativeBooleanArgument(args, index, &result); + return result; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Numbers + +template +struct DartConverterInteger { + static Dart_Handle ToDart(T val) { return Dart_NewInteger(val); } + + static void SetReturnValue(Dart_NativeArguments args, T val) { + Dart_SetIntegerReturnValue(args, val); + } + + static T FromDart(Dart_Handle handle) { + int64_t result = 0; + Dart_IntegerToInt64(handle, &result); + return result; + } + + static T FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception) { + int64_t result = 0; + Dart_GetNativeIntegerArgument(args, index, &result); + return result; + } +}; + +template <> +struct DartConverter : public DartConverterInteger {}; + +template <> +struct DartConverter : public DartConverterInteger {}; + +template <> +struct DartConverter : public DartConverterInteger {}; + +template <> +struct DartConverter { + static Dart_Handle ToDart(unsigned long long val) { + // FIXME: WebIDL unsigned long long is guaranteed to fit into 64-bit + // unsigned, + // so we need a dart API for constructing an integer from uint64_t. + DCHECK(val <= 0x7fffffffffffffffLL); + return Dart_NewInteger(static_cast(val)); + } + + static void SetReturnValue(Dart_NativeArguments args, + unsigned long long val) { + DCHECK(val <= 0x7fffffffffffffffLL); + Dart_SetIntegerReturnValue(args, val); + } + + static unsigned long long FromDart(Dart_Handle handle) { + int64_t result = 0; + Dart_IntegerToInt64(handle, &result); + return result; + } + + static unsigned long long FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception) { + int64_t result = 0; + Dart_GetNativeIntegerArgument(args, index, &result); + return result; + } +}; + +template +struct DartConverterFloatingPoint { + static Dart_Handle ToDart(T val) { return Dart_NewDouble(val); } + + static void SetReturnValue(Dart_NativeArguments args, T val) { + Dart_SetDoubleReturnValue(args, val); + } + + static T FromDart(Dart_Handle handle) { + double result = 0; + Dart_DoubleValue(handle, &result); + return result; + } + + static T FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception) { + double result = 0; + Dart_GetNativeDoubleArgument(args, index, &result); + return result; + } +}; + +template <> +struct DartConverter : public DartConverterFloatingPoint {}; + +template <> +struct DartConverter : public DartConverterFloatingPoint {}; + +//////////////////////////////////////////////////////////////////////////////// +// Strings + +template <> +struct DartConverter { + static Dart_Handle ToDart(DartState* state, const String& val) { + if (val.isEmpty()) + return Dart_EmptyString(); + return Dart_HandleFromWeakPersistent(state->string_cache().Get(val.impl())); + } + + static void SetReturnValue(Dart_NativeArguments args, + const String& val, + bool auto_scope = true) { + // TODO(abarth): What should we do with auto_scope? + if (val.isEmpty()) { + Dart_SetReturnValue(args, Dart_EmptyString()); + return; + } + DartState* state = DartState::Current(); + Dart_SetWeakHandleReturnValue(args, state->string_cache().Get(val.impl())); + } + + static void SetReturnValueWithNullCheck(Dart_NativeArguments args, + const String& val, + bool auto_scope = true) { + if (val.isNull()) + Dart_SetReturnValue(args, Dart_Null()); + else + SetReturnValue(args, val, auto_scope); + } + + static String FromDart(Dart_Handle handle) { + intptr_t char_size = 0; + intptr_t length = 0; + void* peer = nullptr; + Dart_Handle result = + Dart_StringGetProperties(handle, &char_size, &length, &peer); + if (peer) + return String(static_cast(peer)); + if (Dart_IsError(result)) + return String(); + return ExternalizeDartString(handle); + } + + static String FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception, + bool auto_scope = true) { + // TODO(abarth): What should we do with auto_scope? + void* peer = nullptr; + Dart_Handle handle = Dart_GetNativeStringArgument(args, index, &peer); + if (peer) + return reinterpret_cast(peer); + if (Dart_IsError(handle)) + return String(); + return ExternalizeDartString(handle); + } + + static String FromArgumentsWithNullCheck(Dart_NativeArguments args, + int index, + Dart_Handle& exception, + bool auto_scope = true) { + // TODO(abarth): What should we do with auto_scope? + void* peer = nullptr; + Dart_Handle handle = Dart_GetNativeStringArgument(args, index, &peer); + if (peer) + return reinterpret_cast(peer); + if (Dart_IsError(handle) || Dart_IsNull(handle)) + return String(); + return ExternalizeDartString(handle); + } +}; + +template <> +struct DartConverter { + static Dart_Handle ToDart(DartState* state, const AtomicString& val) { + return DartConverter::ToDart(state, val.string()); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Collections + +template +struct DartConverter> { + static Dart_Handle ToDart(const Vector& val) { + Dart_Handle list = Dart_NewList(val.size()); + if (Dart_IsError(list)) + return list; + for (size_t i = 0; i < val.size(); i++) { + Dart_Handle result = + Dart_ListSetAt(list, i, DartConverter::ToDart(val[i])); + if (Dart_IsError(result)) + return result; + } + return list; + } + + static Vector FromDart(Dart_Handle handle) { + Vector result; + if (!Dart_IsList(handle)) + return result; + intptr_t length = 0; + Dart_ListLength(handle, &length); + result.reserveCapacity(length); + for (intptr_t i = 0; i < length; ++i) { + Dart_Handle element = Dart_ListGetAt(handle, i); + DCHECK(!Dart_IsError(element)); + result.append(DartConverter::FromDart(element)); + } + return result; + } + + static Vector FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception, + bool auto_scope = true) { + // TODO(abarth): What should we do with auto_scope? + return FromDart(Dart_GetNativeArgument(args, index)); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// DartValue + +template <> +struct DartConverter { + static Dart_Handle ToDart(DartState* state, DartValue* val) { + return val->dart_value(); + } + + static void SetReturnValue(Dart_NativeArguments args, DartValue* val) { + Dart_SetReturnValue(args, val->dart_value()); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Convience wrappers for commonly used conversions + +inline Dart_Handle StringToDart(DartState* state, const String& val) { + return DartConverter::ToDart(state, val); +} + +inline Dart_Handle StringToDart(DartState* state, const AtomicString& val) { + return DartConverter::ToDart(state, val); +} + +inline String StringFromDart(Dart_Handle handle) { + return DartConverter::FromDart(handle); +} + +//////////////////////////////////////////////////////////////////////////////// +// Convience wrappers using type inference for ease of code generation + +template +inline Dart_Handle VectorToDart(const Vector& val) { + return DartConverter>::ToDart(val); +} + +template +Dart_Handle ToDart(const T& object) { + return DartConverter::ToDart(object); +} + +//////////////////////////////////////////////////////////////////////////////// +// std::string support (slower, but more convienent for some clients) + +inline Dart_Handle StdStringToDart(const std::string& val) { + return Dart_NewStringFromUTF8(reinterpret_cast(val.data()), + val.length()); +} + +inline std::string StdStringFromDart(Dart_Handle handle) { + String string = StringFromDart(handle); + StringUTF8Adaptor utf8(string); + return std::string(utf8.data(), utf8.length()); +} + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_CONVERTER_H_ diff --git a/engine/tonic/dart_error.cc b/engine/tonic/dart_error.cc new file mode 100644 index 00000000000..4ef6865437c --- /dev/null +++ b/engine/tonic/dart_error.cc @@ -0,0 +1,26 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_error.h" + +#include "base/logging.h" + +namespace blink { + +namespace DartError { + +const char kInvalidArgument[] = "Invalid argument."; + +} // namespace DartError + +bool LogIfError(Dart_Handle handle) { + if (Dart_IsError(handle)) { + LOG(ERROR) << Dart_GetError(handle); + return true; + } + return false; +} + +} // namespace blink diff --git a/engine/tonic/dart_error.h b/engine/tonic/dart_error.h new file mode 100644 index 00000000000..52605ce9491 --- /dev/null +++ b/engine/tonic/dart_error.h @@ -0,0 +1,21 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_ERROR_H_ +#define SKY_ENGINE_TONIC_DART_ERROR_H_ + +#include "dart/runtime/include/dart_api.h" + +namespace blink { + +namespace DartError { +extern const char kInvalidArgument[]; +} // namespace DartError + +bool LogIfError(Dart_Handle handle); + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_ERROR_H_ + diff --git a/engine/tonic/dart_gc_context.cc b/engine/tonic/dart_gc_context.cc new file mode 100644 index 00000000000..4d515a37d2c --- /dev/null +++ b/engine/tonic/dart_gc_context.cc @@ -0,0 +1,28 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_gc_context.h" + +namespace blink { + +DartGCContext::DartGCContext() : builder_(Dart_NewWeakReferenceSetBuilder()) { +} + +DartGCContext::~DartGCContext() { +} + +Dart_WeakReferenceSet DartGCContext::AddToSetForRoot( + const void* root, + Dart_WeakPersistentHandle handle) { + const auto& it = references_.add(root, nullptr); + if (!it.isNewEntry) { + Dart_AppendToWeakReferenceSet(it.storedValue->value, handle, handle); + return it.storedValue->value; + } + it.storedValue->value = Dart_NewWeakReferenceSet(builder_, handle, handle); + return it.storedValue->value; +} + +} // namespace blink diff --git a/engine/tonic/dart_gc_context.h b/engine/tonic/dart_gc_context.h new file mode 100644 index 00000000000..4fc9e18d666 --- /dev/null +++ b/engine/tonic/dart_gc_context.h @@ -0,0 +1,31 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_GC_CONTEXT_H_ +#define SKY_ENGINE_TONIC_DART_GC_CONTEXT_H_ + +#include "base/macros.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/wtf/HashMap.h" + +namespace blink { + +class DartGCContext { + public: + DartGCContext(); + ~DartGCContext(); + + Dart_WeakReferenceSet AddToSetForRoot(const void* root, + Dart_WeakPersistentHandle handle); + + private: + Dart_WeakReferenceSetBuilder builder_; + HashMap references_; + + DISALLOW_COPY_AND_ASSIGN(DartGCContext); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_GC_CONTEXT_H_ diff --git a/engine/tonic/dart_gc_controller.cc b/engine/tonic/dart_gc_controller.cc new file mode 100644 index 00000000000..61a830eecd9 --- /dev/null +++ b/engine/tonic/dart_gc_controller.cc @@ -0,0 +1,48 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_gc_controller.h" + +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/tonic/dart_gc_context.h" +#include "sky/engine/tonic/dart_gc_visitor.h" +#include "sky/engine/tonic/dart_wrappable.h" + +namespace blink { +namespace { + +DartGCContext* g_gc_context = nullptr; + +DartWrappable* GetWrappable(intptr_t* fields) { + return reinterpret_cast(fields[DartWrappable::kPeerIndex]); +} + +void Visit(void* isolate_callback_data, + Dart_WeakPersistentHandle handle, + intptr_t native_field_count, + intptr_t* native_fields) { + if (!native_field_count) + return; + DCHECK(native_field_count == DartWrappable::kNumberOfNativeFields); + DartGCVisitor visitor(g_gc_context); + GetWrappable(native_fields)->AcceptDartGCVisitor(visitor); +} + +} // namespace + +void DartGCPrologue() { + Dart_EnterScope(); + DCHECK(!g_gc_context); + g_gc_context = new DartGCContext(); + Dart_VisitPrologueWeakHandles(Visit); +} + +void DartGCEpilogue() { + delete g_gc_context; + g_gc_context = nullptr; + Dart_ExitScope(); +} + +} // namespace blink diff --git a/engine/tonic/dart_gc_controller.h b/engine/tonic/dart_gc_controller.h new file mode 100644 index 00000000000..196d9333431 --- /dev/null +++ b/engine/tonic/dart_gc_controller.h @@ -0,0 +1,15 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_GC_CONTROLLER_H_ +#define SKY_ENGINE_TONIC_DART_GC_CONTROLLER_H_ + +namespace blink { + +void DartGCPrologue(); +void DartGCEpilogue(); + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_GC_CONTROLLER_H_ diff --git a/engine/tonic/dart_gc_visitor.cc b/engine/tonic/dart_gc_visitor.cc new file mode 100644 index 00000000000..bff6d095e30 --- /dev/null +++ b/engine/tonic/dart_gc_visitor.cc @@ -0,0 +1,26 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_gc_visitor.h" + +#include "sky/engine/tonic/dart_gc_context.h" + +namespace blink { + +DartGCVisitor::DartGCVisitor(DartGCContext* context) + : context_(context), current_set_(nullptr) { +} + +DartGCVisitor::~DartGCVisitor() { +} + +void DartGCVisitor::AddToSetForRoot(const void* root, + Dart_WeakPersistentHandle handle) { + Dart_WeakReferenceSet set = context_->AddToSetForRoot(root, handle); + DCHECK(!current_set_ || current_set_ == set); + current_set_ = set; +} + +} // namespace blink diff --git a/engine/tonic/dart_gc_visitor.h b/engine/tonic/dart_gc_visitor.h new file mode 100644 index 00000000000..05b09feec30 --- /dev/null +++ b/engine/tonic/dart_gc_visitor.h @@ -0,0 +1,39 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_GC_VISITOR_H_ +#define SKY_ENGINE_TONIC_DART_GC_VISITOR_H_ + +#include "base/logging.h" +#include "dart/runtime/include/dart_api.h" + +namespace blink { +class DartGCContext; + +class DartGCVisitor { + public: + explicit DartGCVisitor(DartGCContext* context); + ~DartGCVisitor(); + + bool have_found_set() const { + return !!current_set_; + } + + Dart_WeakReferenceSet current_set() const { + DCHECK(have_found_set()); + return current_set_; + } + + void AddToSetForRoot(const void* root, Dart_WeakPersistentHandle handle); + + private: + DartGCContext* context_; + Dart_WeakReferenceSet current_set_; + + DISALLOW_COPY_AND_ASSIGN(DartGCVisitor); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_GC_VISITOR_H_ diff --git a/engine/tonic/dart_isolate_scope.cc b/engine/tonic/dart_isolate_scope.cc new file mode 100644 index 00000000000..884ce41a1f2 --- /dev/null +++ b/engine/tonic/dart_isolate_scope.cc @@ -0,0 +1,29 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_isolate_scope.h" + +namespace blink { + +DartIsolateScope::DartIsolateScope(Dart_Isolate isolate) { + isolate_ = isolate; + previous_ = Dart_CurrentIsolate(); + if (previous_ == isolate_) + return; + if (previous_) + Dart_ExitIsolate(); + Dart_EnterIsolate(isolate_); +} + +DartIsolateScope::~DartIsolateScope() { + DCHECK(Dart_CurrentIsolate() == isolate_); + if (previous_ == isolate_) + return; + Dart_ExitIsolate(); + if (previous_) + Dart_EnterIsolate(previous_); +} + +} // namespace blink diff --git a/engine/tonic/dart_isolate_scope.h b/engine/tonic/dart_isolate_scope.h new file mode 100644 index 00000000000..778fa8e6c3e --- /dev/null +++ b/engine/tonic/dart_isolate_scope.h @@ -0,0 +1,28 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_ISOLATE_SCOPE_H_ +#define SKY_ENGINE_TONIC_DART_ISOLATE_SCOPE_H_ + +#include "base/logging.h" +#include "dart/runtime/include/dart_api.h" + +namespace blink { + +// DartIsolateScope is a helper class for entering and exiting a given isolate. +class DartIsolateScope { + public: + explicit DartIsolateScope(Dart_Isolate isolate); + ~DartIsolateScope(); + + private: + Dart_Isolate isolate_; + Dart_Isolate previous_; + + DISALLOW_COPY_AND_ASSIGN(DartIsolateScope); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_ISOLATE_SCOPE_H_ diff --git a/engine/tonic/dart_persistent_value.cc b/engine/tonic/dart_persistent_value.cc new file mode 100644 index 00000000000..459099a1b73 --- /dev/null +++ b/engine/tonic/dart_persistent_value.cc @@ -0,0 +1,49 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_persistent_value.h" + +#include "sky/engine/tonic/dart_isolate_scope.h" +#include "sky/engine/tonic/dart_state.h" + +namespace blink { + +DartPersistentValue::DartPersistentValue() : value_(nullptr) { +} + +DartPersistentValue::DartPersistentValue(DartState* dart_state, + Dart_Handle value) + : value_(nullptr) { + Set(dart_state, value); +} + +DartPersistentValue::~DartPersistentValue() { + Clear(); +} + +void DartPersistentValue::Set(DartState* dart_state, Dart_Handle value) { + DCHECK(is_empty()); + dart_state_ = dart_state->GetWeakPtr(); + value_ = Dart_NewPersistentHandle(value); +} + +void DartPersistentValue::Clear() { + if (!value_ || !dart_state_.get()) + return; + + DartIsolateScope scope(dart_state_->isolate()); + Dart_DeletePersistentHandle(value_); + dart_state_ = base::WeakPtr(); + value_ = nullptr; +} + +Dart_Handle DartPersistentValue::Release() { + if (!value_) + return nullptr; + Dart_Handle local = Dart_HandleFromPersistent(value_); + Clear(); + return local; +} +} diff --git a/engine/tonic/dart_persistent_value.h b/engine/tonic/dart_persistent_value.h new file mode 100644 index 00000000000..c6215c4b077 --- /dev/null +++ b/engine/tonic/dart_persistent_value.h @@ -0,0 +1,43 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_PERSISTENT_VALUE_H_ +#define SKY_ENGINE_TONIC_DART_PERSISTENT_VALUE_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "dart/runtime/include/dart_api.h" + +namespace blink { +class DartState; + +// DartPersistentValue is a bookkeeping class to help pair calls to +// Dart_NewPersistentHandle with Dart_DeletePersistentHandle. Consider using +// this class instead of holding a Dart_PersistentHandle directly so that you +// don't leak the Dart_PersistentHandle. +class DartPersistentValue { + public: + DartPersistentValue(); + DartPersistentValue(DartState* dart_state, Dart_Handle value); + ~DartPersistentValue(); + + Dart_PersistentHandle value() const { return value_; } + bool is_empty() const { return !value_; } + + void Set(DartState* dart_state, Dart_Handle value); + void Clear(); + Dart_Handle Release(); + + const base::WeakPtr& dart_state() const { return dart_state_; } + + private: + base::WeakPtr dart_state_; + Dart_PersistentHandle value_; + + DISALLOW_COPY_AND_ASSIGN(DartPersistentValue); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_PERSISTENT_VALUE_H_ diff --git a/engine/tonic/dart_state.cc b/engine/tonic/dart_state.cc new file mode 100644 index 00000000000..1ff57f435f1 --- /dev/null +++ b/engine/tonic/dart_state.cc @@ -0,0 +1,42 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_state.h" + +#include "sky/engine/tonic/dart_class_library.h" +#include "sky/engine/tonic/dart_string_cache.h" +#include "sky/engine/wtf/PassOwnPtr.h" + +namespace blink { + +DartState::Scope::Scope(DartState* dart_state) { +} + +DartState::Scope::~Scope() { +} + +DartState::DartState() + : isolate_(NULL), + class_library_(adoptPtr(new DartClassLibrary)), + string_cache_(adoptPtr(new DartStringCache)), + weak_factory_(this) { +} + +DartState::~DartState() { +} + +DartState* DartState::From(Dart_Isolate isolate) { + return static_cast(Dart_IsolateData(isolate)); +} + +DartState* DartState::Current() { + return static_cast(Dart_CurrentIsolateData()); +} + +base::WeakPtr DartState::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +} // namespace blink diff --git a/engine/tonic/dart_state.h b/engine/tonic/dart_state.h new file mode 100644 index 00000000000..88a0b4af86a --- /dev/null +++ b/engine/tonic/dart_state.h @@ -0,0 +1,62 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_STATE_H_ +#define SKY_ENGINE_TONIC_DART_STATE_H_ + +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/supports_user_data.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/wtf/OwnPtr.h" +#include "sky/engine/wtf/PassRefPtr.h" +#include "sky/engine/wtf/RefCounted.h" + +namespace blink { +class DartStringCache; +class DartClassLibrary; + +// DartState represents the state associated with a given Dart isolate. The +// lifetime of this object is controlled by the DartVM. If you want to hold a +// reference to a DartState instance, please hold a base::WeakPtr. +// +// DartState is analogous to gin::PerIsolateData and JSC::ExecState. +class DartState : public base::SupportsUserData { + public: + class Scope { + public: + Scope(DartState* dart_state); + ~Scope(); + }; + + DartState(); + virtual ~DartState(); + + static DartState* From(Dart_Isolate isolate); + static DartState* Current(); + + base::WeakPtr GetWeakPtr(); + + Dart_Isolate isolate() { return isolate_; } + void set_isolate(Dart_Isolate isolate) { + CHECK(!isolate_); + isolate_ = isolate; + } + + DartClassLibrary& class_library() { return *class_library_; } + DartStringCache& string_cache() { return *string_cache_; } + + private: + Dart_Isolate isolate_; + OwnPtr class_library_; + OwnPtr string_cache_; + + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(DartState); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_STATE_H_ diff --git a/engine/tonic/dart_string.cc b/engine/tonic/dart_string.cc new file mode 100644 index 00000000000..98550314cb9 --- /dev/null +++ b/engine/tonic/dart_string.cc @@ -0,0 +1,65 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_string.h" + +#include "base/logging.h" + +namespace blink { +namespace { + +void FinalizeString(void* string_impl) { + DCHECK(string_impl); + reinterpret_cast(string_impl)->deref(); +} + +template +String Externalize(Dart_Handle handle, intptr_t length) { + if (!length) + return StringImpl::empty(); + CharType* buffer = nullptr; + RefPtr string_impl = + StringImpl::createUninitialized(length, buffer); + + string_impl->ref(); // Balanced in FinalizeString. + + Dart_Handle result = + Dart_MakeExternalString(handle, buffer, length * sizeof(CharType), + string_impl.get(), FinalizeString); + DCHECK(!Dart_IsError(result)); + return String(string_impl.release()); +} + +} // namespace + +Dart_Handle CreateDartString(StringImpl* string_impl) { + if (!string_impl) + return Dart_EmptyString(); + + string_impl->ref(); // Balanced in FinalizeString. + + if (string_impl->is8Bit()) { + return Dart_NewExternalLatin1String(string_impl->characters8(), + string_impl->length(), string_impl, + FinalizeString); + } else { + return Dart_NewExternalUTF16String(string_impl->characters16(), + string_impl->length(), string_impl, + FinalizeString); + } +} + +String ExternalizeDartString(Dart_Handle handle) { + DCHECK(Dart_IsString(handle)); + DCHECK(!Dart_IsExternalString(handle)); + bool is_latin1 = Dart_IsStringLatin1(handle); + intptr_t length; + Dart_StringLength(handle, &length); + if (is_latin1) + return Externalize(handle, length); + return Externalize(handle, length); +} + +} // namespace blink diff --git a/engine/tonic/dart_string.h b/engine/tonic/dart_string.h new file mode 100644 index 00000000000..ebe6c5160ba --- /dev/null +++ b/engine/tonic/dart_string.h @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_STRING_H_ +#define SKY_ENGINE_TONIC_DART_STRING_H_ + +#include "base/logging.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/wtf/text/WTFString.h" + +namespace blink { + +Dart_Handle CreateDartString(StringImpl* string_impl); +String ExternalizeDartString(Dart_Handle handle); + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_STRING_H_ diff --git a/engine/tonic/dart_string_cache.cc b/engine/tonic/dart_string_cache.cc new file mode 100644 index 00000000000..d82deb1eb03 --- /dev/null +++ b/engine/tonic/dart_string_cache.cc @@ -0,0 +1,67 @@ +// Copyright 2014 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_string_cache.h" + +#include "sky/engine/tonic/dart_state.h" +#include "sky/engine/tonic/dart_string.h" + +namespace blink { + +DartStringCache::DartStringCache() : last_dart_string_(nullptr) { +} + +DartStringCache::~DartStringCache() { +} + +Dart_WeakPersistentHandle DartStringCache::GetSlow(StringImpl* string_impl, + bool auto_scope) { + if (Dart_WeakPersistentHandle string = cache_.get(string_impl)) { + last_dart_string_ = string; + last_string_impl_ = string_impl; + return string; + } + + if (!auto_scope) + Dart_EnterScope(); + + Dart_Handle string = CreateDartString(string_impl); + DCHECK(!Dart_IsError(string)); + + intptr_t size_in_bytes = string_impl->sizeInBytes(); + Dart_WeakPersistentHandle wrapper = Dart_NewWeakPersistentHandle( + string, string_impl, size_in_bytes, FinalizeCacheEntry); + + string_impl->ref(); // Balanced in FinalizeCacheEntry. + cache_.set(string_impl, wrapper); + + last_dart_string_ = wrapper; + last_string_impl_ = string_impl; + + if (!auto_scope) + Dart_ExitScope(); + + return wrapper; +} + +void DartStringCache::FinalizeCacheEntry(void* isolate_callback_data, + Dart_WeakPersistentHandle handle, + void* peer) { + DartState* state = reinterpret_cast(isolate_callback_data); + StringImpl* string_impl = reinterpret_cast(peer); + DartStringCache& cache = state->string_cache(); + + Dart_WeakPersistentHandle cached_handle = cache.cache_.take(string_impl); + ASSERT_UNUSED(cached_handle, handle == cached_handle); + + if (cache.last_dart_string_ == handle) { + cache.last_dart_string_ = nullptr; + cache.last_string_impl_ = nullptr; + } + + string_impl->deref(); +} + +} // namespace blink diff --git a/engine/tonic/dart_string_cache.h b/engine/tonic/dart_string_cache.h new file mode 100644 index 00000000000..5ec219e12b8 --- /dev/null +++ b/engine/tonic/dart_string_cache.h @@ -0,0 +1,48 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_STRING_CACHE_H_ +#define SKY_ENGINE_TONIC_DART_STRING_CACHE_H_ + +#include "base/logging.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/wtf/HashMap.h" +#include "sky/engine/wtf/RefPtr.h" +#include "sky/engine/wtf/text/StringHash.h" +#include "sky/engine/wtf/text/StringImpl.h" + +namespace blink { + +// DartStringCache maintains a mapping between WTF Strings and Dart strings. +// When you create a Dart string from a WTF String, the underlying character +// data is shared between the two systems. +class DartStringCache { + public: + DartStringCache(); + ~DartStringCache(); + + Dart_WeakPersistentHandle Get(StringImpl* string_impl, + bool auto_scope = true) { + DCHECK(string_impl); + if (last_string_impl_.get() == string_impl) + return last_dart_string_; + return GetSlow(string_impl, auto_scope); + } + + private: + Dart_WeakPersistentHandle GetSlow(StringImpl* string_impl, bool auto_scope); + static void FinalizeCacheEntry(void*, Dart_WeakPersistentHandle, void* peer); + + typedef HashMap StringCache; + + StringCache cache_; + Dart_WeakPersistentHandle last_dart_string_; + RefPtr last_string_impl_; + + DISALLOW_COPY_AND_ASSIGN(DartStringCache); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_STRING_CACHE_H_ diff --git a/engine/tonic/dart_value.cc b/engine/tonic/dart_value.cc new file mode 100644 index 00000000000..e80a8438cbe --- /dev/null +++ b/engine/tonic/dart_value.cc @@ -0,0 +1,33 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_value.h" + +namespace blink { + +DartValue::DartValue() { +} + +DartValue::DartValue(DartState* dart_state, Dart_Handle value) + : dart_value_(dart_state, value) { +} + +DartValue::~DartValue() { +} + +bool DartValue::Equals(DartValue* other) const { + DCHECK(other); + if (is_empty()) + return other->is_empty(); + if (other->is_empty()) + return false; + return Dart_IdentityEquals(dart_value(), other->dart_value()); +} + +void DartValue::Clear() { + dart_value_.Clear(); +} + +} // namespace blink diff --git a/engine/tonic/dart_value.h b/engine/tonic/dart_value.h new file mode 100644 index 00000000000..57332e451b1 --- /dev/null +++ b/engine/tonic/dart_value.h @@ -0,0 +1,59 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_VALUE_H_ +#define SKY_ENGINE_TONIC_DART_VALUE_H_ + +#include "base/logging.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/tonic/dart_persistent_value.h" +#include "sky/engine/tonic/dart_state.h" +#include "sky/engine/wtf/RefPtr.h" + +namespace blink { + +// DartValue is a convience wrapper around DartPersistentValue that lets clients +// use RefPtr to keep track of the number of references to the underlying Dart +// object. Be careful when retaining RefPtr in the heap because the +// VM's garbage collector cannot break cycles that involve the C++ heap, which +// can lead to memory leaks. +class DartValue : public RefCounted { + public: + static PassRefPtr Create(DartState* dart_state, + Dart_Handle value) { + return adoptRef(new DartValue(dart_state, value)); + } + + static PassRefPtr Create() { return adoptRef(new DartValue()); } + + ~DartValue(); + + Dart_Handle dart_value() const { return dart_value_.value(); } + bool is_empty() const { return !dart_value(); } + + bool is_null() const { + DCHECK(!is_empty()); + return Dart_IsNull(dart_value()); + } + + bool is_function() const { + DCHECK(!is_empty()); + return Dart_IsClosure(dart_value()); + } + + bool Equals(DartValue* other) const; + void Clear(); + + private: + DartValue(); + DartValue(DartState* dart_state, Dart_Handle value); + + DartPersistentValue dart_value_; + + DISALLOW_COPY_AND_ASSIGN(DartValue); +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_VALUE_H_ diff --git a/engine/tonic/dart_wrappable.cc b/engine/tonic/dart_wrappable.cc new file mode 100644 index 00000000000..6c7e3a15267 --- /dev/null +++ b/engine/tonic/dart_wrappable.cc @@ -0,0 +1,91 @@ +// Copyright 2015 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 "sky/engine/config.h" +#include "sky/engine/tonic/dart_wrappable.h" + +#include "sky/engine/tonic/dart_class_library.h" +#include "sky/engine/tonic/dart_error.h" +#include "sky/engine/tonic/dart_state.h" +#include "sky/engine/tonic/dart_wrapper_info.h" + +namespace blink { + +DartWrappable::~DartWrappable() { + CHECK(!dart_wrapper_); +} + +void DartWrappable::AcceptDartGCVisitor(DartGCVisitor& visitor) const { +} + +Dart_Handle DartWrappable::CreateDartWrapper(DartState* dart_state) { + DCHECK(!dart_wrapper_); + const DartWrapperInfo& info = GetDartWrapperInfo(); + + Dart_PersistentHandle type = dart_state->class_library().GetClass(info); + DCHECK(!LogIfError(type)); + + intptr_t native_fields[kNumberOfNativeFields]; + native_fields[kPeerIndex] = reinterpret_cast(this); + native_fields[kWrapperInfoIndex] = reinterpret_cast(&info); + Dart_Handle wrapper = + Dart_AllocateWithNativeFields(type, kNumberOfNativeFields, native_fields); + DCHECK(!LogIfError(wrapper)); + + info.ref_object(this); // Balanced in FinalizeDartWrapper. + dart_wrapper_ = Dart_NewPrologueWeakPersistentHandle( + wrapper, this, info.size_in_bytes, &FinalizeDartWrapper); + + return wrapper; +} + +void DartWrappable::FinalizeDartWrapper(void* isolate_callback_data, + Dart_WeakPersistentHandle wrapper, + void* peer) { + DartWrappable* wrappable = reinterpret_cast(peer); + wrappable->dart_wrapper_ = nullptr; + const DartWrapperInfo& info = wrappable->GetDartWrapperInfo(); + info.deref_object(wrappable); // Balanced in CreateDartWrapper. +} + +DartWrappable* DartConverterWrappable::FromDart(Dart_Handle handle) { + intptr_t* peer = 0; + Dart_Handle result = + Dart_GetNativeInstanceField(handle, DartWrappable::kPeerIndex, peer); + if (Dart_IsError(result)) + return nullptr; + return reinterpret_cast(peer); +} + +DartWrappable* DartConverterWrappable::FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception) { + intptr_t native_fields[DartWrappable::kNumberOfNativeFields]; + Dart_Handle result = Dart_GetNativeFieldsOfArgument( + args, index, DartWrappable::kNumberOfNativeFields, native_fields); + if (Dart_IsError(result)) { + exception = Dart_NewStringFromCString(DartError::kInvalidArgument); + return nullptr; + } + return reinterpret_cast( + native_fields[DartWrappable::kPeerIndex]); +} + +DartWrappable* DartConverterWrappable::FromArgumentsWithNullCheck( + Dart_NativeArguments args, int index, Dart_Handle& exception) { + Dart_Handle handle = Dart_GetNativeArgument(args, index); + if (Dart_IsNull(handle)) + return nullptr; + intptr_t native_fields[DartWrappable::kNumberOfNativeFields]; + Dart_Handle result = Dart_GetNativeFieldsOfArgument( + args, index, DartWrappable::kNumberOfNativeFields, native_fields); + if (Dart_IsError(result)) { + exception = Dart_NewStringFromCString(DartError::kInvalidArgument); + return nullptr; + } + return reinterpret_cast( + native_fields[DartWrappable::kPeerIndex]); +} + +} // namespace blink diff --git a/engine/tonic/dart_wrappable.h b/engine/tonic/dart_wrappable.h new file mode 100644 index 00000000000..dba0f182b02 --- /dev/null +++ b/engine/tonic/dart_wrappable.h @@ -0,0 +1,141 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_WRAPPABLE_H_ +#define SKY_ENGINE_TONIC_DART_WRAPPABLE_H_ + +#include "base/logging.h" +#include "base/template_util.h" +#include "dart/runtime/include/dart_api.h" +#include "sky/engine/tonic/dart_converter.h" +#include "sky/engine/tonic/dart_error.h" +#include "sky/engine/tonic/dart_state.h" +#include "sky/engine/tonic/dart_wrapper_info.h" + +namespace blink { +class DartGCVisitor; +struct DartWrapperInfo; + +// DartWrappable is a base class that you can inherit from in order to be +// exposed to Dart code as an interface. +class DartWrappable { + public: + enum DartNativeFields { + kPeerIndex, // Must be first to work with Dart_GetNativeReceiver. + kWrapperInfoIndex, + kNumberOfNativeFields, + }; + + DartWrappable() : dart_wrapper_(nullptr) {} + + // Subclasses that wish to expose a new interface must override this function + // and provide information about their wrapper. There is no need to call your + // base class's implementation of this function. + virtual const DartWrapperInfo& GetDartWrapperInfo() const = 0; + + // Subclasses that wish to integrate with the Dart garbage collector should + // override this function. Please call your base class's AcceptDartGCVisitor + // at the end of your override. + virtual void AcceptDartGCVisitor(DartGCVisitor& visitor) const; + + Dart_Handle CreateDartWrapper(DartState* dart_state); + Dart_WeakPersistentHandle dart_wrapper() const { return dart_wrapper_; } + + protected: + virtual ~DartWrappable(); + + private: + static void FinalizeDartWrapper(void* isolate_callback_data, + Dart_WeakPersistentHandle wrapper, + void* peer); + + Dart_WeakPersistentHandle dart_wrapper_; + + DISALLOW_COPY_AND_ASSIGN(DartWrappable); +}; + +#define DEFINE_WRAPPERTYPEINFO() \ + public: \ + const DartWrapperInfo& GetDartWrapperInfo() const override { \ + return dart_wrapper_info_; \ + } \ + private: \ + static const DartWrapperInfo& dart_wrapper_info_ + +struct DartConverterWrappable { + static DartWrappable* FromDart(Dart_Handle handle); + static DartWrappable* FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception); + static DartWrappable* FromArgumentsWithNullCheck(Dart_NativeArguments args, + int index, + Dart_Handle& exception); +}; + +template +struct DartConverter< + T*, + typename base::enable_if< + base::is_convertible::value>::type> { + static Dart_Handle ToDart(DartWrappable* val) { + if (!val) + return Dart_Null(); + if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) + return Dart_HandleFromWeakPersistent(wrapper); + return val->CreateDartWrapper(DartState::Current()); + } + + static void SetReturnValue(Dart_NativeArguments args, + DartWrappable* val, + bool auto_scope = true) { + if (!val) + Dart_SetReturnValue(args, Dart_Null()); + else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) + Dart_SetWeakHandleReturnValue(args, wrapper); + else + Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current())); + } + + static T* FromDart(Dart_Handle handle) { + // TODO(abarth): We're missing a type check. + return static_cast(DartConverterWrappable::FromDart(handle)); + } + + static T* FromArguments(Dart_NativeArguments args, + int index, + Dart_Handle& exception, + bool auto_scope = true) { + // TODO(abarth): We're missing a type check. + return static_cast(DartConverterWrappable::FromArguments( + args, index, exception)); + } + + static T* FromArgumentsWithNullCheck(Dart_NativeArguments args, + int index, + Dart_Handle& exception, + bool auto_scope = true) { + // TODO(abarth): We're missing a type check. + return static_cast(DartConverterWrappable::FromArgumentsWithNullCheck( + args, index, exception)); + } +}; + +template +struct DartConverter> { + static Dart_Handle ToDart(RefPtr val) { + return DartConverter::ToDart(val.get()); + } +}; + +template +static T* GetReceiver(Dart_NativeArguments args) { + intptr_t receiver; + Dart_Handle result = Dart_GetNativeReceiver(args, &receiver); + DCHECK(!Dart_IsError(result)); + return static_cast(reinterpret_cast(receiver)); +} + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_WRAPPABLE_H_ diff --git a/engine/tonic/dart_wrapper_info.h b/engine/tonic/dart_wrapper_info.h new file mode 100644 index 00000000000..a8e131e6f26 --- /dev/null +++ b/engine/tonic/dart_wrapper_info.h @@ -0,0 +1,28 @@ +// Copyright 2015 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. + +#ifndef SKY_ENGINE_TONIC_DART_WRAPPER_INFO_H_ +#define SKY_ENGINE_TONIC_DART_WRAPPER_INFO_H_ + +#include "base/macros.h" + +namespace blink { +class DartWrappable; + +typedef void (*DartWrappableAccepter)(DartWrappable*); + +struct DartWrapperInfo { + const char* interface_name; + const size_t size_in_bytes; + const DartWrappableAccepter ref_object; + const DartWrappableAccepter deref_object; + + private: + DartWrapperInfo(const DartWrapperInfo&) = delete; + DartWrapperInfo& operator=(const DartWrapperInfo&) = delete; +}; + +} // namespace blink + +#endif // SKY_ENGINE_TONIC_DART_WRAPPER_INFO_H_