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 14 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: 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)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the incoming arg closure is not a closure, don't you need a check that it is a Function Object? further down you are calling Dart_FunctionOwner on it and this method will return an error if it is not a function object.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good catch. I'll add a check.

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
58 changes: 58 additions & 0 deletions lib/ui/plugins.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 {
/// 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 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 _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;
}

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this returns something else to more clearly indicate the error?

}

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
54 changes: 54 additions & 0 deletions lib/ui/plugins/callback_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.

#ifndef FLUTTER_LIB_UI_CALLBACK_CACHE_H_
#define FLUTTER_LIB_UI_CALLBACK_CACHE_H_

#include <map>
#include <mutex>
#include <string>

#include "flutter/fml/synchronization/thread_annotations.h"
#include "lib/fxl/macros.h"
#include "third_party/dart/runtime/include/dart_api.h"

#define DART_CALLBACK_INVALID_HANDLE -1
#define LOCK_UNLOCK(m) FML_ACQUIRE(m) FML_RELEASE(m)

namespace blink {

typedef struct {
std::string name;
std::string class_name;
std::string library_path;
} DartCallbackRepresentation;

class DartCallbackCache {
public:
static int64_t GetCallbackHandle(const std::string& name,
const std::string& class_name,
const std::string& library_path)
LOCK_UNLOCK(mutex_);

static Dart_Handle GetCallback(int64_t handle) LOCK_UNLOCK(mutex_);

static DartCallbackRepresentation GetCallbackInformation(int64_t handle)
LOCK_UNLOCK(mutex_);

private:
static Dart_Handle LookupDartClosure(const std::string& name,
const std::string& class_name,
const std::string& library_path);

static std::mutex mutex_;

static std::map<int64_t, DartCallbackRepresentation> cache_
FML_GUARDED_BY(mutex_);

FXL_DISALLOW_IMPLICIT_CONSTRUCTORS(DartCallbackCache);
};

} // namespace blink

#endif // FLUTTER_LIB_UI_CALLBACK_CACHE_H_
Loading