Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ linter:
# - avoid_bool_literals_in_conditional_expressions # not yet tested
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members
- avoid_classes_with_only_static_members # We want to avoid classes that can be instantiated but only have statics
- avoid_empty_else
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
Expand Down
2 changes: 2 additions & 0 deletions lib/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ source_set("ui") {
"painting/shader.h",
"painting/vertices.cc",
"painting/vertices.h",
"plugins/callback_cache.cc",
"plugins/callback_cache.h",
"semantics/semantics_node.cc",
"semantics/semantics_node.h",
"semantics/semantics_update.cc",
Expand Down
114 changes: 109 additions & 5 deletions lib/ui/dart_runtime_hooks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <sstream>

#include "flutter/common/settings.h"
#include "flutter/lib/ui/plugins/callback_cache.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "lib/fxl/build_config.h"
#include "lib/fxl/logging.h"
Expand All @@ -36,6 +37,7 @@ extern void syslog(int, const char*, ...);
}
#endif

using tonic::DartConverter;
using tonic::LogIfError;
using tonic::ToDart;

Expand All @@ -48,23 +50,25 @@ namespace blink {
#define BUILTIN_NATIVE_LIST(V) \
V(Logger_PrintString, 1) \
V(SaveCompilationTrace, 0) \
V(ScheduleMicrotask, 1)
V(ScheduleMicrotask, 1) \
V(GetCallbackHandle, 1) \
V(GetCallbackFromHandle, 1)

BUILTIN_NATIVE_LIST(DECLARE_FUNCTION);

void DartRuntimeHooks::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)});
}

static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) {
static Dart_Handle GetFunction(Dart_Handle builtin_library, const char* name) {
Dart_Handle getter_name = ToDart(name);
Dart_Handle closure = Dart_Invoke(builtin_library, getter_name, 0, nullptr);
DART_CHECK_VALID(closure);
return closure;
}

static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate) {
Dart_Handle print = GetClosure(builtin_library, "_getPrintClosure");
Dart_Handle print = GetFunction(builtin_library, "_getPrintClosure");

Dart_Handle internal_library = Dart_LookupLibrary(ToDart("dart:_internal"));

Expand Down Expand Up @@ -101,7 +105,7 @@ static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) {
Dart_Handle schedule_microtask;
if (is_ui_isolate) {
schedule_microtask =
GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
GetFunction(builtin_library, "_getScheduleMicrotaskClosure");
} else {
Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
Dart_Handle method_name =
Expand All @@ -125,7 +129,8 @@ static void InitDartIO(Dart_Handle builtin_library,
DART_CHECK_VALID(Dart_SetField(platform_type, ToDart("_nativeScript"),
ToDart(script_uri)));
}
Dart_Handle locale_closure = GetClosure(builtin_library, "_getLocaleClosure");
Dart_Handle locale_closure =
GetFunction(builtin_library, "_getLocaleClosure");
DART_CHECK_VALID(
Dart_SetField(platform_type, ToDart("_localeClosure"), locale_closure));
}
Expand Down Expand Up @@ -223,4 +228,103 @@ void ScheduleMicrotask(Dart_NativeArguments args) {
UIDartState::Current()->ScheduleMicrotask(closure);
}

static std::string GetFunctionLibraryUrl(Dart_Handle closure) {
if (Dart_IsClosure(closure)) {
closure = Dart_ClosureFunction(closure);
DART_CHECK_VALID(closure);
}

if (!Dart_IsFunction(closure)) {
return "";
}

Dart_Handle url = Dart_Null();
Dart_Handle owner = Dart_FunctionOwner(closure);
if (Dart_IsInstance(owner)) {
owner = Dart_ClassLibrary(owner);
}
if (Dart_IsLibrary(owner)) {
url = Dart_LibraryUrl(owner);
DART_CHECK_VALID(url);
}
return DartConverter<std::string>::FromDart(url);
}

static std::string GetFunctionClassName(Dart_Handle closure) {
Dart_Handle result;

if (Dart_IsClosure(closure)) {
closure = Dart_ClosureFunction(closure);
DART_CHECK_VALID(closure);
}

if (!Dart_IsFunction(closure)) {
return "";
}

bool is_static = false;
result = Dart_FunctionIsStatic(closure, &is_static);
DART_CHECK_VALID(result);
if (!is_static) {
return "";
}

result = Dart_FunctionOwner(closure);
DART_CHECK_VALID(result);

if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) {
return "";
}
return DartConverter<std::string>::FromDart(Dart_ClassName(result));
}

static std::string GetFunctionName(Dart_Handle func) {
DART_CHECK_VALID(func);

if (Dart_IsClosure(func)) {
func = Dart_ClosureFunction(func);
DART_CHECK_VALID(func);
}

if (!Dart_IsFunction(func)) {
return "";
}

bool is_static = false;
Dart_Handle result = Dart_FunctionIsStatic(func, &is_static);
DART_CHECK_VALID(result);
if (!is_static) {
return "";
}

result = Dart_FunctionName(func);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
return "";
}

return DartConverter<std::string>::FromDart(result);
}

void GetCallbackHandle(Dart_NativeArguments args) {
Dart_Handle func = Dart_GetNativeArgument(args, 0);
std::string name = GetFunctionName(func);
std::string class_name = GetFunctionClassName(func);
std::string library_path = GetFunctionLibraryUrl(func);

if (name.empty()) {
Dart_SetReturnValue(args, Dart_Null());
return;
}
Dart_SetReturnValue(
args, DartConverter<int64_t>::ToDart(DartCallbackCache::GetCallbackHandle(
name, class_name, library_path)));
}

void GetCallbackFromHandle(Dart_NativeArguments args) {
Dart_Handle h = Dart_GetNativeArgument(args, 0);
int64_t handle = DartConverter<int64_t>::FromDart(h);
Dart_SetReturnValue(args, DartCallbackCache::GetCallback(handle));
}

} // namespace blink
1 change: 1 addition & 0 deletions lib/ui/dart_ui.gni
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dart_ui_files = [
"$flutter_root/lib/ui/lerp.dart",
"$flutter_root/lib/ui/natives.dart",
"$flutter_root/lib/ui/painting.dart",
"$flutter_root/lib/ui/plugins.dart",
"$flutter_root/lib/ui/pointer.dart",
"$flutter_root/lib/ui/semantics.dart",
"$flutter_root/lib/ui/text.dart",
Expand Down
3 changes: 3 additions & 0 deletions lib/ui/natives.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ dynamic _saveCompilationTrace() native 'SaveCompilationTrace';

void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask';

int _getCallbackHandle(Function closure) native 'GetCallbackHandle';
Function _getCallbackFromHandle(int handle) native 'GetCallbackFromHandle';

// Required for gen_snapshot to work correctly.
int _isolateId;

Expand Down
69 changes: 69 additions & 0 deletions lib/ui/plugins.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2018 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.

part of dart.ui;

/// An wrapper for a raw callback handle.
class CallbackHandle {
final int _handle;

/// Create an instance using a raw callback handle.
///
/// Only values produced by a call to [CallbackHandle.toRawHandle] should be
/// used, otherwise this object will be an invalid handle.
CallbackHandle.fromRawHandle(this._handle)
: assert(_handle != null, "'_handle' must not be null.");

/// Get the raw callback handle to pass over a [MethodChannel] or isolate
/// port.
int toRawHandle() => _handle;

@override
int get hashCode => _handle;

@override
bool operator ==(dynamic other) =>
(other is CallbackHandle) && (_handle == other._handle);
}

/// Functionality for Flutter plugin authors.
abstract class PluginUtilities {
// This class is only a namespace, and should not be instantiated or
// extended directly.
factory PluginUtilities._() => null;

static Map<Function, CallbackHandle> _forwardCache =
<Function, CallbackHandle>{};
static Map<CallbackHandle, Function> _backwardCache =
<CallbackHandle, Function>{};

/// Get a handle to a named top-level or static callback function which can
/// be easily passed between isolates.
///
/// `callback` must not be null.
///
/// Returns a [CallbackHandle] that can be provided to
/// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the
/// original callback. If `callback` is not a top-level or static function,
/// null is returned.
static CallbackHandle getCallbackHandle(Function callback) {
assert(callback != null, "'callback' must not be null.");
return _forwardCache.putIfAbsent(callback,
() => new CallbackHandle.fromRawHandle(_getCallbackHandle(callback)));
}

/// Get a tear-off of a named top-level or static callback represented by a
/// handle.
///
/// `handle` must not be null.
///
/// If `handle` is not a valid handle returned by
/// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a
/// tear-off of the callback associated with `handle` is returned.
static Function getCallbackFromHandle(CallbackHandle handle) {
assert(handle != null, "'handle' must not be null.");
return _backwardCache.putIfAbsent(
handle, () => _getCallbackFromHandle(handle.toRawHandle()));
}
}
87 changes: 87 additions & 0 deletions lib/ui/plugins/callback_cache.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2018 The Flutter 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 "flutter/lib/ui/plugins/callback_cache.h"
#include "lib/fxl/logging.h"
#include "lib/tonic/converter/dart_converter.h"

using tonic::ToDart;

namespace blink {

std::mutex DartCallbackCache::mutex_;
std::map<int64_t, DartCallbackRepresentation> DartCallbackCache::cache_;

Dart_Handle DartCallbackCache::GetCallback(int64_t handle) {
std::unique_lock<std::mutex> lock(mutex_);
auto iterator = cache_.find(handle);
if (iterator != cache_.end()) {
DartCallbackRepresentation cb = iterator->second;
return LookupDartClosure(cb.name, cb.class_name, cb.library_path);
}
return Dart_Null();
}

int64_t DartCallbackCache::GetCallbackHandle(const std::string& name,
const std::string& class_name,
const std::string& library_path) {
std::unique_lock<std::mutex> lock(mutex_);
std::hash<std::string> hasher;
int64_t hash = hasher(name);
hash += hasher(class_name);
hash += hasher(library_path);

if (cache_.find(hash) == cache_.end()) {
cache_[hash] = {name, class_name, library_path};
}
return hash;
}

std::unique_ptr<DartCallbackRepresentation>
DartCallbackCache::GetCallbackInformation(int64_t handle) {
std::unique_lock<std::mutex> lock(mutex_);
auto iterator = cache_.find(handle);
if (iterator != cache_.end()) {
return std::make_unique<DartCallbackRepresentation>(iterator->second);
}
return nullptr;
}

Dart_Handle DartCallbackCache::LookupDartClosure(
const std::string& name,
const std::string& class_name,
const std::string& library_path) {
Dart_Handle closure_name = ToDart(name);
Dart_Handle library_name =
library_path.empty() ? Dart_Null() : ToDart(library_path);
Dart_Handle cls_name = class_name.empty() ? Dart_Null() : ToDart(class_name);
DART_CHECK_VALID(closure_name);
DART_CHECK_VALID(library_name);
DART_CHECK_VALID(cls_name);

Dart_Handle library;
if (library_name == Dart_Null()) {
library = Dart_RootLibrary();
} else {
library = Dart_LookupLibrary(library_name);
}
DART_CHECK_VALID(library);

Dart_Handle closure;
if (Dart_IsNull(cls_name)) {
closure = Dart_GetClosure(library, closure_name);
} else {
Dart_Handle cls = Dart_GetClass(library, cls_name);
DART_CHECK_VALID(cls);
if (Dart_IsNull(cls)) {
closure = Dart_Null();
} else {
closure = Dart_GetStaticMethodClosure(library, cls, closure_name);
}
}
DART_CHECK_VALID(closure);
return closure;
}

} // namespace blink
Loading