dart-sdk/runtime/vm/dart_api_impl.h
Daco Harkes f524ec74ce [vm/ffi] FfiNative process lookup
This CL makes `FfiNative`s use `DynamicLibrary.process()` lookup if
resolving with the resolver set by `Dart_SetFfiNativeResolver` fails.

Also moves the implementation over from ffi.cc to
ffi_dynamic_library.cc so the implementation can be shared with
`DynamicLibrary.process()`.

Moves the implementation behind non-simulator and non-precompiler.
However, the implementation is tested in vm/cc tests which are in
precompiler mode. So enables the implementation if TESTED is defined.

This CL massages the build files so that TESTED is properly
defined when compiling the runtime for the vm/cc tests, and links
the ole32 symbols on windows for vm/cc tests.

(And some unrelated small cleanup changes here and there.)

TEST=tests/ffi/native_assets/process_test.dart

Change-Id: I25395d381db1d9b4b7a5759171a798a1140a6140
Cq-Include-Trybots: luci.dart.try:vm-kernel-win-debug-x64c-try,vm-kernel-win-debug-x64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-precomp-win-debug-x64c-try,dart-sdk-win-try,vm-kernel-win-release-x64-try,vm-kernel-win-release-ia32-try,vm-kernel-precomp-win-product-x64-try,vm-kernel-reload-linux-debug-x64-try,vm-kernel-reload-rollback-linux-debug-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264982
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Daco Harkes <dacoharkes@google.com>
2022-10-25 10:57:07 +00:00

367 lines
16 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_DART_API_IMPL_H_
#define RUNTIME_VM_DART_API_IMPL_H_
#include <memory>
#include "vm/allocation.h"
#include "vm/heap/safepoint.h"
#include "vm/native_arguments.h"
#include "vm/object.h"
#include "vm/thread_registry.h"
#include "vm/timeline.h"
namespace dart {
class ApiLocalScope;
class ApiState;
class FinalizablePersistentHandle;
class LocalHandle;
class PersistentHandle;
class ReusableObjectHandleScope;
class ThreadRegistry;
const char* CanonicalFunction(const char* func);
#define CURRENT_FUNC CanonicalFunction(__FUNCTION__)
// Checks that the current isolate group is not NULL.
#define CHECK_ISOLATE_GROUP(isolate_group) \
do { \
if ((isolate_group) == NULL) { \
FATAL1( \
"%s expects there to be a current isolate group. Did you " \
"forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?", \
CURRENT_FUNC); \
} \
} while (0)
// Checks that the current isolate is not NULL.
#define CHECK_ISOLATE(isolate) \
do { \
if ((isolate) == NULL) { \
FATAL1( \
"%s expects there to be a current isolate. Did you " \
"forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?", \
CURRENT_FUNC); \
} \
} while (0)
// Checks that the current isolate is NULL.
#define CHECK_NO_ISOLATE(isolate) \
do { \
if ((isolate) != NULL) { \
FATAL1( \
"%s expects there to be no current isolate. Did you " \
"forget to call Dart_ExitIsolate?", \
CURRENT_FUNC); \
} \
} while (0)
// Checks that the current isolate is not NULL and that it has an API scope.
#define CHECK_API_SCOPE(thread) \
do { \
Thread* tmpT = (thread); \
Isolate* tmpI = tmpT == NULL ? NULL : tmpT->isolate(); \
CHECK_ISOLATE(tmpI); \
if (tmpT->api_top_scope() == NULL) { \
FATAL1( \
"%s expects to find a current scope. Did you forget to call " \
"Dart_EnterScope?", \
CURRENT_FUNC); \
} \
} while (0);
#define DARTSCOPE(thread) \
Thread* T = (thread); \
CHECK_API_SCOPE(T); \
TransitionNativeToVM transition(T); \
HANDLESCOPE(T);
#define RETURN_TYPE_ERROR(zone, dart_handle, type) \
do { \
const Object& tmp = \
Object::Handle(zone, Api::UnwrapHandle((dart_handle))); \
if (tmp.IsNull()) { \
return Api::NewArgumentError("%s expects argument '%s' to be non-null.", \
CURRENT_FUNC, #dart_handle); \
} else if (tmp.IsError()) { \
return dart_handle; \
} \
return Api::NewArgumentError("%s expects argument '%s' to be of type %s.", \
CURRENT_FUNC, #dart_handle, #type); \
} while (0)
#define RETURN_NULL_ERROR(parameter) \
return Api::NewError("%s expects argument '%s' to be non-null.", \
CURRENT_FUNC, #parameter)
#define CHECK_NULL(parameter) \
if (parameter == NULL) { \
RETURN_NULL_ERROR(parameter); \
}
#define CHECK_LENGTH(length, max_elements) \
do { \
intptr_t len = (length); \
intptr_t max = (max_elements); \
if (len < 0 || len > max) { \
return Api::NewError( \
"%s expects argument '%s' to be in the range [0..%" Pd "].", \
CURRENT_FUNC, #length, max); \
} \
} while (0)
#ifdef SUPPORT_TIMELINE
#define API_TIMELINE_DURATION(thread) \
TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC)
#define API_TIMELINE_BEGIN_END(thread) \
TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC)
#else
#define API_TIMELINE_DURATION(thread) \
do { \
} while (false)
#define API_TIMELINE_BEGIN_END(thread) \
do { \
} while (false)
#endif // SUPPORT_TIMELINE
class Api : AllStatic {
public:
// Create on the stack to provide a new throw-safe api scope.
class Scope : public ThreadStackResource {
public:
explicit Scope(Thread* thread) : ThreadStackResource(thread) {
thread->EnterApiScope();
}
~Scope() { thread()->ExitApiScope(); }
private:
DISALLOW_COPY_AND_ASSIGN(Scope);
};
// Creates a new local handle.
static Dart_Handle NewHandle(Thread* thread, ObjectPtr raw);
// Unwraps the raw object from the handle.
static ObjectPtr UnwrapHandle(Dart_Handle object);
// Unwraps a raw Type from the handle. The handle will be null if
// the object was not of the requested Type.
#define DECLARE_UNWRAP(Type) \
static const Type& Unwrap##Type##Handle(Zone* zone, Dart_Handle object);
CLASS_LIST_FOR_HANDLES(DECLARE_UNWRAP)
#undef DECLARE_UNWRAP
// Unwraps the raw object from the handle using a reused handle.
static const String& UnwrapStringHandle(
const ReusableObjectHandleScope& reused,
Dart_Handle object);
static const Instance& UnwrapInstanceHandle(
const ReusableObjectHandleScope& reused,
Dart_Handle object);
// Returns an Error handle if isolate is in an inconsistent state
// or there was an error while finalizing classes.
// Returns a Success handle when no error condition exists.
static Dart_Handle CheckAndFinalizePendingClasses(Thread* thread);
// Casts the internal Isolate* type to the external Dart_Isolate type.
static Dart_Isolate CastIsolate(Isolate* isolate);
// Casts the internal IsolateGroup* type to the external Dart_IsolateGroup
// type.
static Dart_IsolateGroup CastIsolateGroup(IsolateGroup* isolate_group);
// Gets the handle used to designate successful return.
static Dart_Handle Success() { return Api::True(); }
// Returns true if the handle holds a Smi.
static bool IsSmi(Dart_Handle handle) {
// Important: we do not require current thread to be in VM state because
// we do not dereference the handle.
ObjectPtr raw = *(reinterpret_cast<ObjectPtr*>(handle));
return !raw->IsHeapObject();
}
// Returns the value of a Smi.
static intptr_t SmiValue(Dart_Handle handle) {
// Important: we do not require current thread to be in VM state because
// we do not dereference the handle.
ObjectPtr value = *(reinterpret_cast<ObjectPtr*>(handle));
return Smi::Value(static_cast<SmiPtr>(value));
}
// Returns true if the handle holds a Dart Instance.
static bool IsInstance(Dart_Handle handle) {
return !IsInternalOnlyClassId(ClassId(handle));
}
// Returns true if the handle is non-dangling.
static bool IsValid(Dart_Handle handle);
// Returns true if the handle holds an Error.
static bool IsError(Dart_Handle handle) {
return IsErrorClassId(ClassId(handle));
}
static intptr_t ClassId(Dart_Handle handle) {
ObjectPtr raw = UnwrapHandle(handle);
if (!raw->IsHeapObject()) {
return kSmiCid;
}
return raw->GetClassId();
}
// Generates a handle used to designate an error return.
static Dart_Handle NewError(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
static Dart_Handle NewArgumentError(const char* format, ...)
PRINTF_ATTRIBUTE(1, 2);
// Gets a handle to Null.
static Dart_Handle Null() { return null_handle_; }
// Gets a handle to True.
static Dart_Handle True() { return true_handle_; }
// Gets a handle to False.
static Dart_Handle False() { return false_handle_; }
// Gets a handle to EmptyString.
static Dart_Handle EmptyString() { return empty_string_handle_; }
// Gets the handle which holds the pre-created acquired error object.
static Dart_Handle NoCallbacksError() { return no_callbacks_error_handle_; }
// Gets the handle for unwind-is-in-progress error.
static Dart_Handle UnwindInProgressError() {
return unwind_in_progress_error_handle_;
}
static bool IsProtectedHandle(Dart_Handle object) {
if (object == NULL) return false;
return (object == true_handle_) || (object == false_handle_) ||
(object == null_handle_) || (object == empty_string_handle_) ||
(object == no_callbacks_error_handle_) ||
(object == unwind_in_progress_error_handle_);
}
// Retrieves the top ApiLocalScope.
static ApiLocalScope* TopScope(Thread* thread);
// Performs initialization needed by the API.
static void Init();
// Allocates handles for objects in the VM isolate.
static void InitHandles();
// Cleanup
static void Cleanup();
// Helper function to get the peer value of an external string object.
static bool StringGetPeerHelper(NativeArguments* args,
int arg_index,
void** peer);
// Helper function to get the native field from a native receiver argument.
static bool GetNativeReceiver(NativeArguments* args, intptr_t* value);
// Helper function to get the boolean value of a Bool native argument.
static bool GetNativeBooleanArgument(NativeArguments* args,
int arg_index,
bool* value);
// Helper function to get the integer value of a Integer native argument.
static bool GetNativeIntegerArgument(NativeArguments* args,
int arg_index,
int64_t* value);
// Helper function to get the double value of a Double native argument.
static bool GetNativeDoubleArgument(NativeArguments* args,
int arg_index,
double* value);
// Helper function to get the native fields of an Instance native argument.
static bool GetNativeFieldsOfArgument(NativeArguments* args,
int arg_index,
int num_fields,
intptr_t* field_values);
// Helper function to set the return value of native functions.
static void SetReturnValue(NativeArguments* args, Dart_Handle retval) {
args->SetReturnUnsafe(UnwrapHandle(retval));
}
static void SetSmiReturnValue(NativeArguments* args, intptr_t retval) {
args->SetReturnUnsafe(Smi::New(retval));
}
static void SetIntegerReturnValue(NativeArguments* args, int64_t retval) {
args->SetReturnUnsafe(Integer::New(retval));
}
static void SetDoubleReturnValue(NativeArguments* args, double retval) {
args->SetReturnUnsafe(Double::New(retval));
}
static void SetWeakHandleReturnValue(NativeArguments* args,
Dart_WeakPersistentHandle retval);
static StringPtr GetEnvironmentValue(Thread* thread, const String& name);
static bool IsFfiEnabled() { return FLAG_enable_ffi; }
private:
static Dart_Handle InitNewHandle(Thread* thread, ObjectPtr raw);
static StringPtr CallEnvironmentCallback(Thread* thread, const String& name);
// Thread local key used by the API. Currently holds the current
// ApiNativeScope if any.
static ThreadLocalKey api_native_key_;
static Dart_Handle true_handle_;
static Dart_Handle false_handle_;
static Dart_Handle null_handle_;
static Dart_Handle empty_string_handle_;
static Dart_Handle no_callbacks_error_handle_;
static Dart_Handle unwind_in_progress_error_handle_;
friend class ApiNativeScope;
};
// Start a scope in which no Dart API call backs are allowed.
#define START_NO_CALLBACK_SCOPE(thread) thread->IncrementNoCallbackScopeDepth()
// End a no Dart API call backs Scope.
#define END_NO_CALLBACK_SCOPE(thread) \
do { \
thread->DecrementNoCallbackScopeDepth(); \
if (thread->no_callback_scope_depth() == 0) { \
thread->heap()->CheckExternalGC(thread); \
} \
} while (false)
#define CHECK_CALLBACK_STATE(thread) \
if (thread->no_callback_scope_depth() != 0) { \
return reinterpret_cast<Dart_Handle>(Api::NoCallbacksError()); \
} \
if (thread->is_unwind_in_progress()) { \
return reinterpret_cast<Dart_Handle>(Api::UnwindInProgressError()); \
}
#define ASSERT_CALLBACK_STATE(thread) \
ASSERT(thread->no_callback_scope_depth() == 0)
class IsolateGroupSource;
// Creates a new isolate from [source] (which should come from an existing
// isolate).
Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
const char* name,
char** error);
} // namespace dart.
#endif // RUNTIME_VM_DART_API_IMPL_H_