From 2a5e18ff643ba8a959164fbc36275b92a01a6346 Mon Sep 17 00:00:00 2001 From: Rafael Weinstein Date: Thu, 12 Feb 2015 12:55:01 -0800 Subject: [PATCH] Merge the tonic layer from skydart branch back to master The tonic layer is analogous to "gin" for v8. It provides wrappers and helpers around common dart types and implements the basic infrastructure for allowing dart wrappers around sky DOM objects to have proper GC behavior. R=abarth@chromium.org TBR=eseidel BUG= Review URL: https://codereview.chromium.org/924593002 --- engine/tonic/BUILD.gn | 49 ++++ engine/tonic/dart_api_scope.h | 24 ++ engine/tonic/dart_builtin.cc | 50 ++++ engine/tonic/dart_builtin.h | 39 ++++ engine/tonic/dart_class_library.cc | 34 +++ engine/tonic/dart_class_library.h | 33 +++ engine/tonic/dart_class_provider.cc | 13 ++ engine/tonic/dart_class_provider.h | 22 ++ engine/tonic/dart_converter.cc | 8 + engine/tonic/dart_converter.h | 325 ++++++++++++++++++++++++++ engine/tonic/dart_error.cc | 26 +++ engine/tonic/dart_error.h | 21 ++ engine/tonic/dart_gc_context.cc | 28 +++ engine/tonic/dart_gc_context.h | 31 +++ engine/tonic/dart_gc_controller.cc | 48 ++++ engine/tonic/dart_gc_controller.h | 15 ++ engine/tonic/dart_gc_visitor.cc | 26 +++ engine/tonic/dart_gc_visitor.h | 39 ++++ engine/tonic/dart_isolate_scope.cc | 29 +++ engine/tonic/dart_isolate_scope.h | 28 +++ engine/tonic/dart_persistent_value.cc | 49 ++++ engine/tonic/dart_persistent_value.h | 43 ++++ engine/tonic/dart_state.cc | 42 ++++ engine/tonic/dart_state.h | 62 +++++ engine/tonic/dart_string.cc | 65 ++++++ engine/tonic/dart_string.h | 19 ++ engine/tonic/dart_string_cache.cc | 67 ++++++ engine/tonic/dart_string_cache.h | 48 ++++ engine/tonic/dart_value.cc | 33 +++ engine/tonic/dart_value.h | 59 +++++ engine/tonic/dart_wrappable.cc | 91 ++++++++ engine/tonic/dart_wrappable.h | 141 +++++++++++ engine/tonic/dart_wrapper_info.h | 28 +++ 33 files changed, 1635 insertions(+) create mode 100644 engine/tonic/BUILD.gn create mode 100644 engine/tonic/dart_api_scope.h create mode 100644 engine/tonic/dart_builtin.cc create mode 100644 engine/tonic/dart_builtin.h create mode 100644 engine/tonic/dart_class_library.cc create mode 100644 engine/tonic/dart_class_library.h create mode 100644 engine/tonic/dart_class_provider.cc create mode 100644 engine/tonic/dart_class_provider.h create mode 100644 engine/tonic/dart_converter.cc create mode 100644 engine/tonic/dart_converter.h create mode 100644 engine/tonic/dart_error.cc create mode 100644 engine/tonic/dart_error.h create mode 100644 engine/tonic/dart_gc_context.cc create mode 100644 engine/tonic/dart_gc_context.h create mode 100644 engine/tonic/dart_gc_controller.cc create mode 100644 engine/tonic/dart_gc_controller.h create mode 100644 engine/tonic/dart_gc_visitor.cc create mode 100644 engine/tonic/dart_gc_visitor.h create mode 100644 engine/tonic/dart_isolate_scope.cc create mode 100644 engine/tonic/dart_isolate_scope.h create mode 100644 engine/tonic/dart_persistent_value.cc create mode 100644 engine/tonic/dart_persistent_value.h create mode 100644 engine/tonic/dart_state.cc create mode 100644 engine/tonic/dart_state.h create mode 100644 engine/tonic/dart_string.cc create mode 100644 engine/tonic/dart_string.h create mode 100644 engine/tonic/dart_string_cache.cc create mode 100644 engine/tonic/dart_string_cache.h create mode 100644 engine/tonic/dart_value.cc create mode 100644 engine/tonic/dart_value.h create mode 100644 engine/tonic/dart_wrappable.cc create mode 100644 engine/tonic/dart_wrappable.h create mode 100644 engine/tonic/dart_wrapper_info.h 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_