mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
![Daco Harkes](/assets/img/avatar_default.png)
This CL implements `NativeFinalizer` in the GC. `FinalizerEntry`s are extended to track `external_size` and in which `Heap::Space` the finalizable value is. On attaching a native finalizer, the external size is added to the relevant heap. When the finalizable value is promoted from new to old space, the external size is promoted as well. And when a native finalizer is run or is detached, the external size is removed from the relevant heap again. In contrast to Dart `Finalizer`s, `NativeFinalizer`s are run on isolate shutdown. When the `NativeFinalizer`s themselves are collected, the finalizers are not run. Users should stick the native finalizer in a global variable to ensure finalization. We will revisit this design when we add send and exit support, because there is a design space to explore what to do in that case. This current solution promises the least to users. In this implementation native finalizers have a Dart entry to clean up the entries from the `all_entries` field of the finalizer. We should consider using another data structure that avoids the need for this Dart entry. See the TODO left in the code. Bug: https://github.com/dart-lang/sdk/issues/47777 TEST=runtime/tests/vm/dart(_2)/isolates/fast_object_copy_test.dart TEST=runtime/vm/object_test.cc TEST=tests/ffi(_2)/vmspecific_native_finalizer_* Change-Id: I8f594c80c3c344ad83e1f2de10de028eb8456121 Cq-Include-Trybots: luci.dart.try:vm-kernel-reload-rollback-linux-debug-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-ffi-android-debug-arm64c-try,dart-sdk-mac-arm64-try,vm-kernel-mac-release-arm64-try,pkg-mac-release-arm64-try,vm-kernel-precomp-nnbd-mac-release-arm64-try,vm-kernel-win-debug-x64c-try,vm-kernel-win-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,vm-kernel-nnbd-win-release-ia32-try,vm-ffi-android-debug-arm-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-mac-debug-x64-try,vm-kernel-nnbd-mac-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,benchmark-linux-try,flutter-frontend-try,pkg-linux-debug-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-gcc-linux-try,vm-kernel-optcounter-threshold-linux-release-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-x64c-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/236320 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
183 lines
7.8 KiB
C++
183 lines
7.8 KiB
C++
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_VM_NATIVE_ENTRY_H_
|
|
#define RUNTIME_VM_NATIVE_ENTRY_H_
|
|
|
|
#include "platform/memory_sanitizer.h"
|
|
|
|
#include "vm/allocation.h"
|
|
#include "vm/exceptions.h"
|
|
#include "vm/heap/verifier.h"
|
|
#include "vm/log.h"
|
|
#include "vm/native_arguments.h"
|
|
#include "vm/native_function.h"
|
|
#include "vm/runtime_entry.h"
|
|
|
|
namespace dart {
|
|
|
|
// Forward declarations.
|
|
class Class;
|
|
class String;
|
|
|
|
#ifdef DEBUG
|
|
#define TRACE_NATIVE_CALL(format, name) \
|
|
if (FLAG_trace_natives) { \
|
|
THR_Print("Calling native: " format "\n", name); \
|
|
}
|
|
#else
|
|
#define TRACE_NATIVE_CALL(format, name) \
|
|
do { \
|
|
} while (0)
|
|
#endif
|
|
|
|
typedef ObjectPtr (*BootstrapNativeFunction)(Thread* thread,
|
|
Zone* zone,
|
|
NativeArguments* arguments);
|
|
|
|
#define DEFINE_NATIVE_ENTRY(name, type_argument_count, argument_count) \
|
|
static ObjectPtr DN_Helper##name(Isolate* isolate, Thread* thread, \
|
|
Zone* zone, NativeArguments* arguments); \
|
|
ObjectPtr BootstrapNatives::DN_##name(Thread* thread, Zone* zone, \
|
|
NativeArguments* arguments) { \
|
|
TRACE_NATIVE_CALL("%s", "" #name); \
|
|
ASSERT(arguments->NativeArgCount() == argument_count); \
|
|
/* Note: a longer type arguments vector may be passed */ \
|
|
ASSERT(arguments->NativeTypeArgCount() >= type_argument_count); \
|
|
return DN_Helper##name(thread->isolate(), thread, zone, arguments); \
|
|
} \
|
|
static ObjectPtr DN_Helper##name(Isolate* isolate, Thread* thread, \
|
|
Zone* zone, NativeArguments* arguments)
|
|
|
|
#define DEFINE_FFI_NATIVE_ENTRY(name, return_type, argument_types) \
|
|
return_type BootstrapNatives::FN_##name argument_types
|
|
|
|
// Helpers that throw an argument exception.
|
|
void DartNativeThrowTypeArgumentCountException(int num_type_args,
|
|
int num_type_args_expected);
|
|
void DartNativeThrowArgumentException(const Instance& instance);
|
|
|
|
// Native should throw an exception if the wrong number of type arguments is
|
|
// passed.
|
|
#define NATIVE_TYPE_ARGUMENT_COUNT(expected) \
|
|
int __num_type_arguments = arguments->NativeTypeArgCount(); \
|
|
if (__num_type_arguments != expected) { \
|
|
DartNativeThrowTypeArgumentCountException(__num_type_arguments, expected); \
|
|
}
|
|
|
|
#define GET_NATIVE_TYPE_ARGUMENT(name, value) \
|
|
AbstractType& name = AbstractType::Handle(value);
|
|
|
|
// Natives should throw an exception if an illegal argument or null is passed.
|
|
// type name = value.
|
|
#define GET_NON_NULL_NATIVE_ARGUMENT(type, name, value) \
|
|
const Instance& __##name##_instance__ = \
|
|
Instance::CheckedHandle(zone, value); \
|
|
if (!__##name##_instance__.Is##type()) { \
|
|
DartNativeThrowArgumentException(__##name##_instance__); \
|
|
} \
|
|
const type& name = type::Cast(__##name##_instance__);
|
|
|
|
// Natives should throw an exception if an illegal argument is passed.
|
|
// type name = value.
|
|
#define GET_NATIVE_ARGUMENT(type, name, value) \
|
|
const Instance& __##name##_instance__ = \
|
|
Instance::CheckedHandle(zone, value); \
|
|
type& name = type::Handle(zone); \
|
|
if (!__##name##_instance__.IsNull()) { \
|
|
if (!__##name##_instance__.Is##type()) { \
|
|
DartNativeThrowArgumentException(__##name##_instance__); \
|
|
} \
|
|
} \
|
|
name ^= value;
|
|
|
|
// Helper class for resolving and handling native functions.
|
|
class NativeEntry : public AllStatic {
|
|
public:
|
|
static const intptr_t kNumArguments = 1;
|
|
static const intptr_t kNumCallWrapperArguments = 2;
|
|
|
|
// Resolve specified dart native function to the actual native entrypoint.
|
|
static NativeFunction ResolveNative(const Library& library,
|
|
const String& function_name,
|
|
int number_of_arguments,
|
|
bool* auto_setup_scope);
|
|
static const uint8_t* ResolveSymbolInLibrary(const Library& library,
|
|
uword pc);
|
|
static const uint8_t* ResolveSymbol(uword pc);
|
|
|
|
static uword BootstrapNativeCallWrapperEntry();
|
|
static void BootstrapNativeCallWrapper(Dart_NativeArguments args,
|
|
Dart_NativeFunction func);
|
|
|
|
static uword NoScopeNativeCallWrapperEntry();
|
|
static void NoScopeNativeCallWrapper(Dart_NativeArguments args,
|
|
Dart_NativeFunction func);
|
|
|
|
static uword AutoScopeNativeCallWrapperEntry();
|
|
static void AutoScopeNativeCallWrapper(Dart_NativeArguments args,
|
|
Dart_NativeFunction func);
|
|
|
|
static uword LinkNativeCallEntry();
|
|
static void LinkNativeCall(Dart_NativeArguments args);
|
|
|
|
private:
|
|
static void NoScopeNativeCallWrapperNoStackCheck(Dart_NativeArguments args,
|
|
Dart_NativeFunction func);
|
|
static void AutoScopeNativeCallWrapperNoStackCheck(Dart_NativeArguments args,
|
|
Dart_NativeFunction func);
|
|
|
|
static bool ReturnValueIsError(NativeArguments* arguments);
|
|
static void PropagateErrors(NativeArguments* arguments);
|
|
};
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
class NativeEntryData : public ValueObject {
|
|
public:
|
|
explicit NativeEntryData(const TypedData& data) : data_(data) {}
|
|
|
|
MethodRecognizer::Kind kind() const;
|
|
void set_kind(MethodRecognizer::Kind value) const;
|
|
static MethodRecognizer::Kind GetKind(TypedDataPtr data);
|
|
|
|
NativeFunctionWrapper trampoline() const;
|
|
void set_trampoline(NativeFunctionWrapper value) const;
|
|
static NativeFunctionWrapper GetTrampoline(TypedDataPtr data);
|
|
|
|
NativeFunction native_function() const;
|
|
void set_native_function(NativeFunction value) const;
|
|
static NativeFunction GetNativeFunction(TypedDataPtr data);
|
|
|
|
intptr_t argc_tag() const;
|
|
void set_argc_tag(intptr_t value) const;
|
|
static intptr_t GetArgcTag(TypedDataPtr data);
|
|
|
|
static TypedDataPtr New(MethodRecognizer::Kind kind,
|
|
NativeFunctionWrapper trampoline,
|
|
NativeFunction native_function,
|
|
intptr_t argc_tag);
|
|
|
|
private:
|
|
struct Payload {
|
|
NativeFunctionWrapper trampoline;
|
|
NativeFunction native_function;
|
|
intptr_t argc_tag;
|
|
MethodRecognizer::Kind kind;
|
|
};
|
|
|
|
static Payload* FromTypedArray(TypedDataPtr data);
|
|
|
|
const TypedData& data_;
|
|
|
|
friend class ObjectPoolSerializationCluster;
|
|
DISALLOW_COPY_AND_ASSIGN(NativeEntryData);
|
|
};
|
|
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_NATIVE_ENTRY_H_
|