dart-sdk/runtime/vm/native_entry.h
Daco Harkes 532c116cd2 [vm] Implement NativeFinalizer
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>
2022-03-26 09:41:21 +00:00

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_