1111#include < tchar.h>
1212#endif
1313
14- #include " include/dart_api.h"
1514#include " vm/bootstrap_natives.h"
15+ #include " vm/dart_api_impl.h"
1616#include " vm/exceptions.h"
1717#include " vm/globals.h"
1818#include " vm/native_entry.h"
19+ #include " vm/object_store.h"
1920
2021#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
2122 defined (DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
2425
2526namespace dart {
2627
27- #if defined(USING_SIMULATOR) || defined(DART_PRECOMPILER)
28+ #if defined(USING_SIMULATOR) || ( defined(DART_PRECOMPILER) && !defined(TESTING) )
2829
2930DART_NORETURN static void SimulatorUnsupported () {
31+ #if defined(USING_SIMULATOR)
3032 Exceptions::ThrowUnsupportedError (
3133 " Not supported on simulated architectures." );
34+ #else
35+ Exceptions::ThrowUnsupportedError (" Not supported in precompiler." );
36+ #endif
3237}
3338
3439DEFINE_NATIVE_ENTRY (Ffi_dl_open, 0 , 1 ) {
@@ -50,17 +55,26 @@ DEFINE_NATIVE_ENTRY(Ffi_dl_providesSymbol, 0, 2) {
5055 SimulatorUnsupported ();
5156}
5257
53- #else // defined(USING_SIMULATOR) || defined(DART_PRECOMPILER)
58+ DEFINE_NATIVE_ENTRY (Ffi_GetFfiNativeResolver, 1 , 0 ) {
59+ SimulatorUnsupported ();
60+ }
5461
55- static void * LoadDynamicLibrary (const char * library_file) {
56- char * error = nullptr ;
57- void * handle = Utils::LoadDynamicLibrary (library_file, &error);
58- if (error != nullptr ) {
59- const String& msg = String::Handle (String::NewFormatted (
60- " Failed to load dynamic library '%s': %s" ,
61- library_file != nullptr ? library_file : " <process>" , error));
62- free (error);
63- Exceptions::ThrowArgumentError (msg);
62+ #else // defined(USING_SIMULATOR) || \
63+ // (defined(DART_PRECOMPILER) && !defined(TESTING))
64+
65+ // If an error occurs populates |error| (if provided) with an error message
66+ // (caller must free this message when it is no longer needed).
67+ static void * LoadDynamicLibrary (const char * library_file,
68+ char ** error = nullptr ) {
69+ char * utils_error = nullptr ;
70+ void * handle = Utils::LoadDynamicLibrary (library_file, &utils_error);
71+ if (utils_error != nullptr ) {
72+ if (error != nullptr ) {
73+ *error = OS::SCreate (
74+ /* use malloc*/ nullptr , " Failed to load dynamic library '%s': %s" ,
75+ library_file != nullptr ? library_file : " <process>" , utils_error);
76+ }
77+ free (utils_error);
6478 }
6579 return handle;
6680}
@@ -71,6 +85,8 @@ const nullptr_t kWindowsDynamicLibraryProcessPtr = nullptr;
7185
7286void * co_task_mem_alloced = nullptr ;
7387
88+ // If an error occurs populates |error| with an error message
89+ // (caller must free this message when it is no longer needed).
7490void * LookupSymbolInProcess (const char * symbol, char ** error) {
7591 // Force loading ole32.dll.
7692 if (co_task_mem_alloced == nullptr ) {
@@ -101,31 +117,22 @@ void* LookupSymbolInProcess(const char* symbol, char** error) {
101117 CloseHandle (current_process);
102118
103119 *error = OS::SCreate (
104- nullptr ,
120+ nullptr , // Use `malloc`.
105121 " None of the loaded modules contained the requested symbol '%s'." ,
106122 symbol);
107123 return nullptr ;
108124}
109125#endif
110126
111- static void * ResolveSymbol (void * handle, const char * symbol) {
112- char * error = nullptr ;
113- #if !defined(DART_HOST_OS_WINDOWS)
114- void * const result =
115- Utils::ResolveSymbolInDynamicLibrary (handle, symbol, &error);
116- #else
117- void * const result =
118- handle == kWindowsDynamicLibraryProcessPtr
119- ? LookupSymbolInProcess (symbol, &error)
120- : Utils::ResolveSymbolInDynamicLibrary (handle, symbol, &error);
121- #endif
122- if (error != nullptr ) {
123- const String& msg = String::Handle (String::NewFormatted (
124- " Failed to lookup symbol '%s': %s" , symbol, error));
125- free (error);
126- Exceptions::ThrowArgumentError (msg);
127+ // If an error occurs populates |error| with an error message
128+ // (caller must free this message when it is no longer needed).
129+ static void * ResolveSymbol (void * handle, const char * symbol, char ** error) {
130+ #if defined(DART_HOST_OS_WINDOWS)
131+ if (handle == kWindowsDynamicLibraryProcessPtr ) {
132+ return LookupSymbolInProcess (symbol, error);
127133 }
128- return result;
134+ #endif
135+ return Utils::ResolveSymbolInDynamicLibrary (handle, symbol, error);
129136}
130137
131138static bool SymbolExists (void * handle, const char * symbol) {
@@ -149,8 +156,13 @@ static bool SymbolExists(void* handle, const char* symbol) {
149156DEFINE_NATIVE_ENTRY (Ffi_dl_open, 0 , 1 ) {
150157 GET_NON_NULL_NATIVE_ARGUMENT (String, lib_path, arguments->NativeArgAt (0 ));
151158
152- void * handle = LoadDynamicLibrary (lib_path.ToCString ());
153-
159+ char * error = nullptr ;
160+ void * handle = LoadDynamicLibrary (lib_path.ToCString (), &error);
161+ if (error != nullptr ) {
162+ const String& msg = String::Handle (String::New (error));
163+ free (error);
164+ Exceptions::ThrowArgumentError (msg);
165+ }
154166 return DynamicLibrary::New (handle);
155167}
156168
@@ -176,8 +188,15 @@ DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) {
176188
177189 void * handle = dlib.GetHandle ();
178190
179- const uword pointer =
180- reinterpret_cast <uword>(ResolveSymbol (handle, argSymbolName.ToCString ()));
191+ char * error = nullptr ;
192+ const uword pointer = reinterpret_cast <uword>(
193+ ResolveSymbol (handle, argSymbolName.ToCString (), &error));
194+ if (error != nullptr ) {
195+ const String& msg = String::Handle (String::NewFormatted (
196+ " Failed to lookup symbol '%s': %s" , argSymbolName.ToCString (), error));
197+ free (error);
198+ Exceptions::ThrowArgumentError (msg);
199+ }
181200 return Pointer::New (type_arg, pointer);
182201}
183202
@@ -197,6 +216,86 @@ DEFINE_NATIVE_ENTRY(Ffi_dl_providesSymbol, 0, 2) {
197216 return Bool::Get (SymbolExists (handle, argSymbolName.ToCString ())).ptr ();
198217}
199218
200- #endif // defined(USING_SIMULATOR)
219+ // nullptr if no native resolver is installed.
220+ static Dart_FfiNativeResolver GetFfiNativeResolver (Thread* const thread,
221+ const String& lib_url_str) {
222+ const Library& lib =
223+ Library::Handle (Library::LookupLibrary (thread, lib_url_str));
224+ if (lib.IsNull ()) {
225+ // It is not an error to not have a native resolver installed.
226+ return nullptr ;
227+ }
228+ return lib.ffi_native_resolver ();
229+ }
230+
231+ // If an error occurs populates |error| with an error message
232+ // (caller must free this message when it is no longer needed).
233+ static void * FfiResolveWithFfiNativeResolver (Thread* const thread,
234+ Dart_FfiNativeResolver resolver,
235+ const String& symbol,
236+ intptr_t args_n,
237+ char ** error) {
238+ auto * result = resolver (symbol.ToCString (), args_n);
239+ if (result == nullptr ) {
240+ *error = OS::SCreate (/* use malloc*/ nullptr ,
241+ " Couldn't resolve function: '%s'" , symbol.ToCString ());
242+ }
243+ return result;
244+ }
245+
246+ // Frees |error|.
247+ static void ThrowFfiResolveError (const String& symbol,
248+ const String& asset,
249+ char * error) {
250+ const String& error_message = String::Handle (String::NewFormatted (
251+ " Couldn't resolve native function '%s' in '%s' : %s.\n " ,
252+ symbol.ToCString (), asset.ToCString (), error));
253+ free (error);
254+ Exceptions::ThrowArgumentError (error_message);
255+ }
256+
257+ // FFI native C function pointer resolver.
258+ static intptr_t FfiResolve (Dart_Handle asset_handle,
259+ Dart_Handle symbol_handle,
260+ uintptr_t args_n) {
261+ auto * const thread = Thread::Current ();
262+ DARTSCOPE (thread);
263+ auto * const zone = thread->zone ();
264+ const String& asset = Api::UnwrapStringHandle (zone, asset_handle);
265+ const String& symbol = Api::UnwrapStringHandle (zone, symbol_handle);
266+ char * error = nullptr ;
267+
268+ // Resolver resolution.
269+ auto resolver = GetFfiNativeResolver (thread, asset);
270+ if (resolver != nullptr ) {
271+ void * ffi_native_result = FfiResolveWithFfiNativeResolver (
272+ thread, resolver, symbol, args_n, &error);
273+ if (error != nullptr ) {
274+ ThrowFfiResolveError (symbol, asset, error);
275+ }
276+ return reinterpret_cast <intptr_t >(ffi_native_result);
277+ }
278+
279+ // Resolution in current process.
280+ #if !defined(DART_HOST_OS_WINDOWS)
281+ void * const result = Utils::ResolveSymbolInDynamicLibrary (
282+ RTLD_DEFAULT, symbol.ToCString (), &error);
283+ #else
284+ void * const result = LookupSymbolInProcess (symbol.ToCString (), &error);
285+ #endif
286+ if (error != nullptr ) {
287+ ThrowFfiResolveError (symbol, asset, error);
288+ }
289+ return reinterpret_cast <intptr_t >(result);
290+ }
291+
292+ // Bootstrap to get the FFI Native resolver through a `native` call.
293+ DEFINE_NATIVE_ENTRY (Ffi_GetFfiNativeResolver, 1 , 0 ) {
294+ GET_NATIVE_TYPE_ARGUMENT (type_arg, arguments->NativeTypeArgAt (0 ));
295+ return Pointer::New (type_arg, reinterpret_cast <intptr_t >(FfiResolve));
296+ }
297+
298+ #endif // defined(USING_SIMULATOR) || \
299+ // (defined(DART_PRECOMPILER) && !defined(TESTING))
201300
202301} // namespace dart
0 commit comments