1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "include/dart_api.h" |
6 | #include "include/dart_api_dl.h" |
7 | #include "include/dart_native_api.h" |
8 | #include "include/dart_version.h" |
9 | #include "include/internal/dart_api_dl_impl.h" |
10 | #include "platform/globals.h" |
11 | #include "vm/bootstrap_natives.h" |
12 | #include "vm/class_finalizer.h" |
13 | #include "vm/class_id.h" |
14 | #include "vm/compiler/ffi/native_type.h" |
15 | #include "vm/exceptions.h" |
16 | #include "vm/flags.h" |
17 | #include "vm/log.h" |
18 | #include "vm/native_arguments.h" |
19 | #include "vm/native_entry.h" |
20 | #include "vm/object.h" |
21 | #include "vm/object_store.h" |
22 | #include "vm/symbols.h" |
23 | |
24 | #if !defined(DART_PRECOMPILED_RUNTIME) |
25 | #include "vm/compiler/assembler/assembler.h" |
26 | #include "vm/compiler/ffi/call.h" |
27 | #include "vm/compiler/ffi/callback.h" |
28 | #include "vm/compiler/jit/compiler.h" |
29 | #endif // !defined(DART_PRECOMPILED_RUNTIME) |
30 | |
31 | namespace dart { |
32 | |
33 | // The following functions are runtime checks on type arguments. |
34 | // Some checks are also performed in kernel transformation, these are asserts. |
35 | // Some checks are only performed at runtime to allow for generic code, these |
36 | // throw ArgumentExceptions. |
37 | |
38 | static bool IsPointerType(const AbstractType& type) { |
39 | return IsFfiPointerClassId(type.type_class_id()); |
40 | } |
41 | |
42 | static void CheckSized(const AbstractType& type_arg) { |
43 | const classid_t type_cid = type_arg.type_class_id(); |
44 | if (IsFfiNativeTypeTypeClassId(type_cid) || IsFfiTypeVoidClassId(type_cid) || |
45 | IsFfiTypeNativeFunctionClassId(type_cid)) { |
46 | const String& error = String::Handle(String::NewFormatted( |
47 | "%s does not have a predefined size (@unsized). " |
48 | "Unsized NativeTypes do not support [sizeOf] because their size " |
49 | "is unknown. " |
50 | "Consequently, [allocate], [Pointer.load], [Pointer.store], and " |
51 | "[Pointer.elementAt] are not available." , |
52 | String::Handle(type_arg.UserVisibleName()).ToCString())); |
53 | Exceptions::ThrowArgumentError(error); |
54 | } |
55 | } |
56 | |
57 | // The following functions are runtime checks on arguments. |
58 | |
59 | static const Integer& AsInteger(const Instance& instance) { |
60 | if (!instance.IsInteger()) { |
61 | const String& error = String::Handle(String::NewFormatted( |
62 | "Expected an int but found %s" , instance.ToCString())); |
63 | Exceptions::ThrowArgumentError(error); |
64 | } |
65 | return Integer::Cast(instance); |
66 | } |
67 | |
68 | static const Double& AsDouble(const Instance& instance) { |
69 | if (!instance.IsDouble()) { |
70 | const String& error = String::Handle(String::NewFormatted( |
71 | "Expected a double but found %s" , instance.ToCString())); |
72 | Exceptions::ThrowArgumentError(error); |
73 | } |
74 | return Double::Cast(instance); |
75 | } |
76 | |
77 | // Calculate the size of a native type. |
78 | // |
79 | // You must check [IsConcreteNativeType] and [CheckSized] first to verify that |
80 | // this type has a defined size. |
81 | static size_t SizeOf(const AbstractType& type, Zone* zone) { |
82 | if (IsFfiTypeClassId(type.type_class_id())) { |
83 | return compiler::ffi::NativeType::FromAbstractType(type, zone) |
84 | .SizeInBytes(); |
85 | } else { |
86 | Class& struct_class = Class::Handle(type.type_class()); |
87 | Object& result = Object::Handle( |
88 | struct_class.InvokeGetter(Symbols::SizeOfStructField(), |
89 | /*throw_nsm_if_absent=*/false, |
90 | /*respect_reflectable=*/false)); |
91 | ASSERT(!result.IsNull() && result.IsInteger()); |
92 | return Integer::Cast(result).AsInt64Value(); |
93 | } |
94 | } |
95 | |
96 | // The remainder of this file implements the dart:ffi native methods. |
97 | |
98 | DEFINE_NATIVE_ENTRY(Ffi_fromAddress, 1, 1) { |
99 | GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); |
100 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, arg_ptr, arguments->NativeArgAt(0)); |
101 | return Pointer::New(type_arg, arg_ptr.AsInt64Value()); |
102 | } |
103 | |
104 | DEFINE_NATIVE_ENTRY(Ffi_address, 0, 1) { |
105 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); |
106 | return Integer::New(pointer.NativeAddress()); |
107 | } |
108 | |
109 | static ObjectPtr LoadValueNumeric(Zone* zone, |
110 | const Pointer& target, |
111 | classid_t type_cid, |
112 | const Integer& offset) { |
113 | // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr. |
114 | const size_t address = |
115 | target.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value()); |
116 | switch (type_cid) { |
117 | case kFfiInt8Cid: |
118 | return Integer::New(*reinterpret_cast<int8_t*>(address)); |
119 | case kFfiInt16Cid: |
120 | return Integer::New(*reinterpret_cast<int16_t*>(address)); |
121 | case kFfiInt32Cid: |
122 | return Integer::New(*reinterpret_cast<int32_t*>(address)); |
123 | case kFfiInt64Cid: |
124 | return Integer::New(*reinterpret_cast<int64_t*>(address)); |
125 | case kFfiUint8Cid: |
126 | return Integer::NewFromUint64(*reinterpret_cast<uint8_t*>(address)); |
127 | case kFfiUint16Cid: |
128 | return Integer::NewFromUint64(*reinterpret_cast<uint16_t*>(address)); |
129 | case kFfiUint32Cid: |
130 | return Integer::NewFromUint64(*reinterpret_cast<uint32_t*>(address)); |
131 | case kFfiUint64Cid: |
132 | return Integer::NewFromUint64(*reinterpret_cast<uint64_t*>(address)); |
133 | case kFfiIntPtrCid: |
134 | return Integer::New(*reinterpret_cast<intptr_t*>(address)); |
135 | case kFfiFloatCid: |
136 | return Double::New(*reinterpret_cast<float_t*>(address)); |
137 | case kFfiDoubleCid: |
138 | return Double::New(*reinterpret_cast<double_t*>(address)); |
139 | default: |
140 | UNREACHABLE(); |
141 | } |
142 | } |
143 | |
144 | #define DEFINE_NATIVE_ENTRY_LOAD(type) \ |
145 | DEFINE_NATIVE_ENTRY(Ffi_load##type, 0, 2) { \ |
146 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \ |
147 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1)); \ |
148 | return LoadValueNumeric(zone, pointer, kFfi##type##Cid, offset); \ |
149 | } |
150 | CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_LOAD) |
151 | #undef DEFINE_NATIVE_ENTRY_LOAD |
152 | |
153 | DEFINE_NATIVE_ENTRY(Ffi_loadPointer, 1, 2) { |
154 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); |
155 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1)); |
156 | |
157 | const auto& pointer_type_arg = |
158 | AbstractType::Handle(zone, pointer.type_argument()); |
159 | const AbstractType& type_arg = |
160 | AbstractType::Handle(TypeArguments::Handle(pointer_type_arg.arguments()) |
161 | .TypeAt(Pointer::kNativeTypeArgPos)); |
162 | |
163 | // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr. |
164 | const size_t address = |
165 | pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value()); |
166 | |
167 | return Pointer::New(type_arg, *reinterpret_cast<uword*>(address)); |
168 | } |
169 | |
170 | static ObjectPtr LoadValueStruct(Zone* zone, |
171 | const Pointer& target, |
172 | const AbstractType& instance_type_arg) { |
173 | // Result is a struct class -- find <class name>.#fromPointer |
174 | // constructor and call it. |
175 | const Class& cls = Class::Handle(zone, instance_type_arg.type_class()); |
176 | const Function& constructor = |
177 | Function::Handle(cls.LookupFunctionAllowPrivate(String::Handle( |
178 | String::Concat(String::Handle(String::Concat( |
179 | String::Handle(cls.Name()), Symbols::Dot())), |
180 | Symbols::StructFromPointer())))); |
181 | ASSERT(!constructor.IsNull()); |
182 | ASSERT(constructor.IsGenerativeConstructor()); |
183 | ASSERT(!Object::Handle(constructor.VerifyCallEntryPoint()).IsError()); |
184 | const Instance& new_object = Instance::Handle(Instance::New(cls)); |
185 | ASSERT(cls.is_allocated() || Dart::vm_snapshot_kind() != Snapshot::kFullAOT); |
186 | const Array& args = Array::Handle(zone, Array::New(2)); |
187 | args.SetAt(0, new_object); |
188 | args.SetAt(1, target); |
189 | const Object& constructorResult = |
190 | Object::Handle(DartEntry::InvokeFunction(constructor, args)); |
191 | ASSERT(!constructorResult.IsError()); |
192 | return new_object.raw(); |
193 | } |
194 | |
195 | DEFINE_NATIVE_ENTRY(Ffi_loadStruct, 0, 2) { |
196 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); |
197 | const AbstractType& pointer_type_arg = |
198 | AbstractType::Handle(pointer.type_argument()); |
199 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); |
200 | |
201 | // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr. |
202 | const size_t address = |
203 | pointer.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) * |
204 | SizeOf(pointer_type_arg, zone); |
205 | const Pointer& pointer_offset = |
206 | Pointer::Handle(zone, Pointer::New(pointer_type_arg, address)); |
207 | |
208 | return LoadValueStruct(zone, pointer_offset, pointer_type_arg); |
209 | } |
210 | |
211 | static void StoreValueNumeric(Zone* zone, |
212 | const Pointer& pointer, |
213 | classid_t type_cid, |
214 | const Integer& offset, |
215 | const Instance& new_value) { |
216 | // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr. |
217 | const size_t address = |
218 | pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value()); |
219 | switch (type_cid) { |
220 | case kFfiInt8Cid: |
221 | *reinterpret_cast<int8_t*>(address) = AsInteger(new_value).AsInt64Value(); |
222 | break; |
223 | case kFfiInt16Cid: |
224 | *reinterpret_cast<int16_t*>(address) = |
225 | AsInteger(new_value).AsInt64Value(); |
226 | break; |
227 | case kFfiInt32Cid: |
228 | *reinterpret_cast<int32_t*>(address) = |
229 | AsInteger(new_value).AsInt64Value(); |
230 | break; |
231 | case kFfiInt64Cid: |
232 | *reinterpret_cast<int64_t*>(address) = |
233 | AsInteger(new_value).AsInt64Value(); |
234 | break; |
235 | case kFfiUint8Cid: |
236 | *reinterpret_cast<uint8_t*>(address) = |
237 | AsInteger(new_value).AsInt64Value(); |
238 | break; |
239 | case kFfiUint16Cid: |
240 | *reinterpret_cast<uint16_t*>(address) = |
241 | AsInteger(new_value).AsInt64Value(); |
242 | break; |
243 | case kFfiUint32Cid: |
244 | *reinterpret_cast<uint32_t*>(address) = |
245 | AsInteger(new_value).AsInt64Value(); |
246 | break; |
247 | case kFfiUint64Cid: |
248 | *reinterpret_cast<uint64_t*>(address) = |
249 | AsInteger(new_value).AsInt64Value(); |
250 | break; |
251 | case kFfiIntPtrCid: |
252 | *reinterpret_cast<intptr_t*>(address) = |
253 | AsInteger(new_value).AsInt64Value(); |
254 | break; |
255 | case kFfiFloatCid: |
256 | *reinterpret_cast<float*>(address) = AsDouble(new_value).value(); |
257 | break; |
258 | case kFfiDoubleCid: |
259 | *reinterpret_cast<double*>(address) = AsDouble(new_value).value(); |
260 | break; |
261 | default: |
262 | UNREACHABLE(); |
263 | } |
264 | } |
265 | |
266 | #define DEFINE_NATIVE_ENTRY_STORE(type) \ |
267 | DEFINE_NATIVE_ENTRY(Ffi_store##type, 0, 3) { \ |
268 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \ |
269 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1)); \ |
270 | GET_NON_NULL_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(2)); \ |
271 | StoreValueNumeric(zone, pointer, kFfi##type##Cid, offset, value); \ |
272 | return Object::null(); \ |
273 | } |
274 | CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_STORE) |
275 | #undef DEFINE_NATIVE_ENTRY_STORE |
276 | |
277 | DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 3) { |
278 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); |
279 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1)); |
280 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, new_value, arguments->NativeArgAt(2)); |
281 | AbstractType& pointer_type_arg = |
282 | AbstractType::Handle(pointer.type_argument()); |
283 | |
284 | auto& new_value_type = |
285 | AbstractType::Handle(zone, new_value.GetType(Heap::kNew)); |
286 | if (!new_value_type.IsSubtypeOf(pointer_type_arg, Heap::kNew)) { |
287 | const String& error = String::Handle(String::NewFormatted( |
288 | "New value (%s) is not a subtype of '%s'." , |
289 | String::Handle(new_value_type.UserVisibleName()).ToCString(), |
290 | String::Handle(pointer_type_arg.UserVisibleName()).ToCString())); |
291 | Exceptions::ThrowArgumentError(error); |
292 | } |
293 | |
294 | ASSERT(IsPointerType(pointer_type_arg)); |
295 | // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr. |
296 | const size_t address = |
297 | pointer.NativeAddress() + static_cast<intptr_t>(offset.AsInt64Value()); |
298 | *reinterpret_cast<uword*>(address) = new_value.NativeAddress(); |
299 | return Object::null(); |
300 | } |
301 | |
302 | DEFINE_NATIVE_ENTRY(Ffi_sizeOf, 1, 0) { |
303 | GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); |
304 | CheckSized(type_arg); |
305 | |
306 | return Integer::New(SizeOf(type_arg, zone)); |
307 | } |
308 | |
309 | // Static invocations to this method are translated directly in streaming FGB |
310 | // and bytecode FGB. However, we can still reach this entrypoint in the bytecode |
311 | // interpreter. |
312 | DEFINE_NATIVE_ENTRY(Ffi_asFunctionInternal, 2, 1) { |
313 | #if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) |
314 | UNREACHABLE(); |
315 | #else |
316 | ASSERT(FLAG_enable_interpreter); |
317 | |
318 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); |
319 | GET_NATIVE_TYPE_ARGUMENT(dart_type, arguments->NativeTypeArgAt(0)); |
320 | GET_NATIVE_TYPE_ARGUMENT(native_type, arguments->NativeTypeArgAt(1)); |
321 | |
322 | const Function& dart_signature = |
323 | Function::Handle(zone, Type::Cast(dart_type).signature()); |
324 | const Function& native_signature = |
325 | Function::Handle(zone, Type::Cast(native_type).signature()); |
326 | const Function& function = Function::Handle( |
327 | compiler::ffi::TrampolineFunction(dart_signature, native_signature)); |
328 | |
329 | // Set the c function pointer in the context of the closure rather than in |
330 | // the function so that we can reuse the function for each c function with |
331 | // the same signature. |
332 | const Context& context = Context::Handle(Context::New(1)); |
333 | context.SetAt(0, pointer); |
334 | |
335 | return Closure::New(Object::null_type_arguments(), |
336 | Object::null_type_arguments(), function, context, |
337 | Heap::kOld); |
338 | #endif |
339 | } |
340 | |
341 | DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) { |
342 | GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); |
343 | GET_NON_NULL_NATIVE_ARGUMENT(Integer, count, arguments->NativeArgAt(1)); |
344 | const auto& pointer_type_arg = AbstractType::Handle(pointer.type_argument()); |
345 | const classid_t type_cid = pointer_type_arg.type_class_id(); |
346 | classid_t cid = 0; |
347 | |
348 | switch (type_cid) { |
349 | case kFfiInt8Cid: |
350 | cid = kExternalTypedDataInt8ArrayCid; |
351 | break; |
352 | case kFfiUint8Cid: |
353 | cid = kExternalTypedDataUint8ArrayCid; |
354 | break; |
355 | case kFfiInt16Cid: |
356 | cid = kExternalTypedDataInt16ArrayCid; |
357 | break; |
358 | case kFfiUint16Cid: |
359 | cid = kExternalTypedDataUint16ArrayCid; |
360 | break; |
361 | case kFfiInt32Cid: |
362 | cid = kExternalTypedDataInt32ArrayCid; |
363 | break; |
364 | case kFfiUint32Cid: |
365 | cid = kExternalTypedDataUint32ArrayCid; |
366 | break; |
367 | case kFfiInt64Cid: |
368 | cid = kExternalTypedDataInt64ArrayCid; |
369 | break; |
370 | case kFfiUint64Cid: |
371 | cid = kExternalTypedDataUint64ArrayCid; |
372 | break; |
373 | case kFfiIntPtrCid: |
374 | cid = kWordSize == 4 ? kExternalTypedDataInt32ArrayCid |
375 | : kExternalTypedDataInt64ArrayCid; |
376 | break; |
377 | case kFfiFloatCid: |
378 | cid = kExternalTypedDataFloat32ArrayCid; |
379 | break; |
380 | case kFfiDoubleCid: |
381 | cid = kExternalTypedDataFloat64ArrayCid; |
382 | break; |
383 | default: { |
384 | const String& error = String::Handle( |
385 | String::NewFormatted("Cannot create a TypedData from a Pointer to %s" , |
386 | pointer_type_arg.ToCString())); |
387 | Exceptions::ThrowArgumentError(error); |
388 | UNREACHABLE(); |
389 | } |
390 | } |
391 | |
392 | const intptr_t element_count = count.AsInt64Value(); |
393 | |
394 | if (element_count < 0 || |
395 | element_count > ExternalTypedData::MaxElements(cid)) { |
396 | const String& error = String::Handle( |
397 | String::NewFormatted("Count must be in the range [0, %" Pd "]." , |
398 | ExternalTypedData::MaxElements(cid))); |
399 | Exceptions::ThrowArgumentError(error); |
400 | } |
401 | |
402 | // The address must be aligned by the element size. |
403 | const intptr_t element_size = ExternalTypedData::ElementSizeFor(cid); |
404 | if (!Utils::IsAligned(pointer.NativeAddress(), element_size)) { |
405 | const String& error = String::Handle( |
406 | String::NewFormatted("Pointer address must be aligned to a multiple of" |
407 | "the element size (%" Pd ")." , |
408 | element_size)); |
409 | Exceptions::ThrowArgumentError(error); |
410 | } |
411 | |
412 | const auto& typed_data_class = |
413 | Class::Handle(zone, isolate->class_table()->At(cid)); |
414 | const auto& error = |
415 | Error::Handle(zone, typed_data_class.EnsureIsFinalized(thread)); |
416 | if (!error.IsNull()) { |
417 | Exceptions::PropagateError(error); |
418 | } |
419 | |
420 | // We disable msan initialization check because the memory may not be |
421 | // initialized yet - dart code might do that later on. |
422 | return ExternalTypedData::New( |
423 | cid, reinterpret_cast<uint8_t*>(pointer.NativeAddress()), element_count, |
424 | Heap::kNew, /*perform_eager_msan_initialization_check=*/false); |
425 | } |
426 | |
427 | DEFINE_NATIVE_ENTRY(Ffi_nativeCallbackFunction, 1, 2) { |
428 | #if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) |
429 | // Calls to this function are removed by the flow-graph builder in AOT. |
430 | // See StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction(). |
431 | UNREACHABLE(); |
432 | #else |
433 | GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); |
434 | GET_NON_NULL_NATIVE_ARGUMENT(Closure, closure, arguments->NativeArgAt(0)); |
435 | GET_NON_NULL_NATIVE_ARGUMENT(Instance, exceptional_return, |
436 | arguments->NativeArgAt(1)); |
437 | |
438 | ASSERT(type_arg.IsInstantiated() && type_arg.IsFunctionType()); |
439 | const Function& native_signature = |
440 | Function::Handle(zone, Type::Cast(type_arg).signature()); |
441 | Function& func = Function::Handle(zone, closure.function()); |
442 | |
443 | // The FE verifies that the target of a 'fromFunction' is a static method, so |
444 | // the value we see here must be a static tearoff. See ffi_use_sites.dart for |
445 | // details. |
446 | // |
447 | // TODO(36748): Define hot-reload semantics of native callbacks. We may need |
448 | // to look up the target by name. |
449 | ASSERT(func.IsImplicitClosureFunction()); |
450 | func = func.parent_function(); |
451 | ASSERT(func.is_static()); |
452 | |
453 | // We are returning an object which is not an Instance here. This is only OK |
454 | // because we know that the result will be passed directly to |
455 | // _pointerFromFunction and will not leak out into user code. |
456 | arguments->SetReturn( |
457 | Function::Handle(zone, compiler::ffi::NativeCallbackFunction( |
458 | native_signature, func, exceptional_return))); |
459 | |
460 | // Because we have already set the return value. |
461 | return Object::sentinel().raw(); |
462 | #endif |
463 | } |
464 | |
465 | DEFINE_NATIVE_ENTRY(Ffi_pointerFromFunction, 1, 1) { |
466 | GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); |
467 | const Function& function = |
468 | Function::CheckedHandle(zone, arguments->NativeArg0()); |
469 | |
470 | Code& code = Code::Handle(zone); |
471 | |
472 | #if defined(DART_PRECOMPILED_RUNTIME) |
473 | code = function.CurrentCode(); |
474 | #else |
475 | // We compile the callback immediately because we need to return a pointer to |
476 | // the entry-point. Native calls do not use patching like Dart calls, so we |
477 | // cannot compile it lazily. |
478 | const Object& result = Object::Handle( |
479 | zone, Compiler::CompileOptimizedFunction(thread, function)); |
480 | if (result.IsError()) { |
481 | Exceptions::PropagateError(Error::Cast(result)); |
482 | } |
483 | ASSERT(result.IsCode()); |
484 | code ^= result.raw(); |
485 | #endif |
486 | |
487 | ASSERT(!code.IsNull()); |
488 | thread->SetFfiCallbackCode(function.FfiCallbackId(), code); |
489 | |
490 | uword entry_point = code.EntryPoint(); |
491 | #if !defined(DART_PRECOMPILED_RUNTIME) |
492 | if (NativeCallbackTrampolines::Enabled()) { |
493 | entry_point = isolate->native_callback_trampolines()->TrampolineForId( |
494 | function.FfiCallbackId()); |
495 | } |
496 | #endif |
497 | |
498 | return Pointer::New(type_arg, entry_point); |
499 | } |
500 | |
501 | DEFINE_NATIVE_ENTRY(DartNativeApiFunctionPointer, 0, 1) { |
502 | GET_NON_NULL_NATIVE_ARGUMENT(String, name_dart, arguments->NativeArgAt(0)); |
503 | const char* name = name_dart.ToCString(); |
504 | |
505 | #define RETURN_FUNCTION_ADDRESS(function_name, R, A) \ |
506 | if (strcmp(name, #function_name) == 0) { \ |
507 | return Integer::New(reinterpret_cast<intptr_t>(function_name)); \ |
508 | } |
509 | DART_NATIVE_API_DL_SYMBOLS(RETURN_FUNCTION_ADDRESS) |
510 | #undef RETURN_FUNCTION_ADDRESS |
511 | |
512 | const String& error = String::Handle( |
513 | String::NewFormatted("Unknown dart_native_api.h symbol: %s." , name)); |
514 | Exceptions::ThrowArgumentError(error); |
515 | } |
516 | |
517 | DEFINE_NATIVE_ENTRY(DartApiDLMajorVersion, 0, 0) { |
518 | return Integer::New(DART_API_DL_MAJOR_VERSION); |
519 | } |
520 | |
521 | DEFINE_NATIVE_ENTRY(DartApiDLMinorVersion, 0, 0) { |
522 | return Integer::New(DART_API_DL_MINOR_VERSION); |
523 | } |
524 | |
525 | static const DartApiEntry dart_api_entries[] = { |
526 | #define ENTRY(name, R, A) \ |
527 | DartApiEntry{#name, reinterpret_cast<void (*)()>(name)}, |
528 | DART_API_ALL_DL_SYMBOLS(ENTRY) |
529 | #undef ENTRY |
530 | DartApiEntry{nullptr, nullptr}}; |
531 | |
532 | static const DartApi dart_api_data = { |
533 | DART_API_DL_MAJOR_VERSION, DART_API_DL_MINOR_VERSION, dart_api_entries}; |
534 | |
535 | DEFINE_NATIVE_ENTRY(DartApiDLInitializeData, 0, 0) { |
536 | return Integer::New(reinterpret_cast<intptr_t>(&dart_api_data)); |
537 | } |
538 | |
539 | } // namespace dart |
540 | |