Skip to content
Permalink
Browse files

[vm / library] Foreign function interface prototype

Prototype for `dart:ffi` on Linux/MacOS x64 in JIT mode.
`dart:ffi` is experimental and its API is likely to change in the future.
Progress and design decisions are tracked in https://github.com/dart-lang/sdk/projects/13


issue: #34452
Change-Id: Ifa4566388e42c8757f154741d11e303465ef305d
Cq-Include-Trybots: luci.dart.try:vm-kernel-optcounter-threshold-linux-release-x64-try, vm-kernel-precomp-linux-debug-x64-try, vm-kernel-precomp-linux-release-simarm-try, vm-kernel-precomp-linux-release-simarm64-try, vm-kernel-precomp-linux-release-x64-try, vm-kernel-precomp-mac-release-simarm64-try, vm-kernel-precomp-win-release-x64-try, vm-kernel-mac-debug-x64-try, vm-kernel-asan-linux-release-x64
Reviewed-on: https://dart-review.googlesource.com/c/80124
Reviewed-by: Samir Jindel <sjindel@google.com>
Auto-Submit: Daco Harkes <dacoharkes@google.com>
  • Loading branch information...
dcharkes authored and sjindel-google committed Feb 13, 2019
1 parent 671865c commit 7d46d4b5cb72e4d957a614ff2b35551dc06b6560
Showing with 6,792 additions and 52 deletions.
  1. +4 −0 .gitignore
  2. +2 −0 BUILD.gn
  3. +5 −0 pkg/dev_compiler/tool/input_sdk/libraries.dart
  4. +5 −2 pkg/front_end/lib/src/api_unstable/vm.dart
  5. +95 −22 pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
  6. +3 −2 pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
  7. +5 −2 pkg/front_end/messages.status
  8. +20 −5 pkg/front_end/messages.yaml
  9. +4 −0 pkg/kernel/lib/ast.dart
  10. +96 −0 pkg/kernel/lib/core_types.dart
  11. +197 −0 pkg/kernel/lib/transformations/ffi.dart
  12. +372 −0 pkg/kernel/lib/transformations/ffi_definitions.dart
  13. +270 −0 pkg/kernel/lib/transformations/ffi_use_sites.dart
  14. +14 −0 pkg/vm/lib/target/vm.dart
  15. +44 −0 runtime/bin/BUILD.gn
  16. +13 −0 runtime/bin/ffi_test_dynamic_library.cc
  17. +368 −0 runtime/bin/ffi_test_functions.cc
  18. +680 −0 runtime/lib/ffi.cc
  19. +114 −0 runtime/lib/ffi_dynamic_library.cc
  20. +35 −0 runtime/lib/ffi_dynamic_library_patch.dart
  21. +69 −0 runtime/lib/ffi_native_type_patch.dart
  22. +55 −0 runtime/lib/ffi_patch.dart
  23. +17 −0 runtime/lib/ffi_sources.gni
  24. +11 −8 runtime/vm/BUILD.gn
  25. +5 −0 runtime/vm/bootstrap_natives.cc
  26. +16 −1 runtime/vm/bootstrap_natives.h
  27. +10 −0 runtime/vm/class_finalizer.cc
  28. +28 −0 runtime/vm/class_id.h
  29. +4 −0 runtime/vm/compiler/assembler/assembler_x64.h
  30. +1 −0 runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
  31. +1 −0 runtime/vm/compiler/frontend/scope_builder.cc
  32. +3 −0 runtime/vm/compiler/jit/compiler.cc
  33. +27 −0 runtime/vm/constants_x64.cc
  34. +37 −0 runtime/vm/constants_x64.h
  35. +4 −0 runtime/vm/dart_api_impl.cc
  36. +19 −0 runtime/vm/dart_api_impl.h
  37. +564 −0 runtime/vm/ffi_trampoline_stubs_x64.cc
  38. +1 −0 runtime/vm/flag_list.h
  39. +4 −0 runtime/vm/kernel_loader.cc
  40. +1 −1 runtime/vm/native_arguments.h
  41. +8 −0 runtime/vm/native_entry.cc
  42. +14 −1 runtime/vm/native_entry.h
  43. +203 −5 runtime/vm/object.cc
  44. +123 −0 runtime/vm/object.h
  45. +18 −0 runtime/vm/object_service.cc
  46. +5 −1 runtime/vm/object_store.h
  47. +16 −0 runtime/vm/raw_object.cc
  48. +94 −0 runtime/vm/raw_object.h
  49. +5 −1 runtime/vm/raw_object_fields.cc
  50. +48 −0 runtime/vm/raw_object_snapshot.cc
  51. +5 −0 runtime/vm/runtime_entry.cc
  52. +1 −0 runtime/vm/runtime_entry_list.h
  53. +7 −0 runtime/vm/service.cc
  54. +8 −0 runtime/vm/snapshot.cc
  55. +1 −0 runtime/vm/snapshot.h
  56. +21 −1 runtime/vm/symbols.h
  57. +2 −0 runtime/vm/vm_sources.gni
  58. +40 −0 samples/ffi/coordinate.dart
  59. +274 −0 samples/ffi/sample_ffi_data.dart
  60. +21 −0 samples/ffi/sample_ffi_dynamic_library.dart
  61. +267 −0 samples/ffi/sample_ffi_functions.dart
  62. +80 −0 samples/ffi/sample_ffi_functions_callbacks.dart
  63. +64 −0 samples/ffi/sample_ffi_functions_structs.dart
  64. +63 −0 samples/ffi/sample_ffi_structs.dart
  65. +1 −0 sdk/BUILD.gn
  66. +5 −0 sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
  67. +50 −0 sdk/lib/ffi/annotations.dart
  68. +32 −0 sdk/lib/ffi/dynamic_library.dart
  69. +102 −0 sdk/lib/ffi/ffi.dart
  70. +12 −0 sdk/lib/ffi/ffi_sources.gni
  71. +133 −0 sdk/lib/ffi/native_type.dart
  72. +8 −0 sdk/lib/libraries.json
  73. +7 −0 sdk/lib/libraries.yaml
  74. +40 −0 tests/standalone_2/ffi/coordinate.dart
  75. +20 −0 tests/standalone_2/ffi/coordinate_bare.dart
  76. +44 −0 tests/standalone_2/ffi/coordinate_manual.dart
  77. +32 −0 tests/standalone_2/ffi/cstring.dart
  78. +29 −0 tests/standalone_2/ffi/data_not_asan_test.dart
  79. +492 −0 tests/standalone_2/ffi/data_test.dart
  80. +63 −0 tests/standalone_2/ffi/dynamic_library_test.dart
  81. +20 −0 tests/standalone_2/ffi/enable_ffi_test.dart
  82. +90 −0 tests/standalone_2/ffi/function_callbacks_test.dart
  83. +116 −0 tests/standalone_2/ffi/function_structs_test.dart
  84. +284 −0 tests/standalone_2/ffi/function_test.dart
  85. +365 −0 tests/standalone_2/ffi/static_checks_test.dart
  86. +136 −0 tests/standalone_2/ffi/structs_test.dart
  87. +19 −0 tests/standalone_2/ffi/subtype_test.dart
  88. +67 −0 tests/standalone_2/ffi/very_large_struct.dart
  89. +14 −0 tests/standalone_2/standalone_2_vm.status
@@ -37,6 +37,7 @@
.idea
CMakeLists.txt
.clang_complete
cmake-build-debug

# VSCode project files
.vscode
@@ -49,6 +50,9 @@ compile_commands.json
# GDB files
.gdb_history

# https://github.com/Dart-Code/Dart-Code/issues/1295
analysis_options.yaml

# Built by chromebot and downloaded from Google Storage
client/tests/drt

@@ -47,6 +47,8 @@ group("runtime") {
"runtime/bin:sample_extension",
"runtime/bin:test_extension",
"runtime/bin:entrypoints_verification_test_extension",
"runtime/bin:ffi_test_dynamic_library",
"runtime/bin:ffi_test_functions",
"runtime/vm:kernel_platform_files($host_toolchain)",
"utils/kernel-service:kernel-service",
]
@@ -61,6 +61,11 @@ const Map<String, LibraryInfo> libraries = const {
categories: "Client,Server,Embedded",
maturity: Maturity.UNSTABLE,
dart2jsPatchPath: "_internal/js_runtime/lib/developer_patch.dart"),
"ffi": const LibraryInfo("ffi/ffi.dart",
categories: "Server",
// TODO(dacoharkes): Update maturity when we release dart:ffi.
// https://github.com/dart-lang/sdk/issues/34452
maturity: Maturity.EXPERIMENTAL),
"html": const LibraryInfo("html/dart2js/html_dart2js.dart",
categories: "Client",
maturity: Maturity.WEB_STABLE,
@@ -53,10 +53,13 @@ export '../fasta/fasta_codes.dart'
templateConstEvalNonConstantLiteral,
templateConstEvalNonConstantVariableGet,
templateConstEvalZeroDivisor,
templateFfiAnnotationMissing,
templateFfiFieldAnnotation,
templateFfiStructAnnotation,
templateFfiNotStatic,
templateFfiTypeInvalid,
templateFfiTypeMismatch,
templateFfiTypeOpaque;
templateFfiTypeUnsized,
templateFfiFieldInitializer;

export '../fasta/hybrid_file_system.dart' show HybridFileSystem;

@@ -3348,28 +3348,101 @@ const MessageCode messageFastaUsageShort =

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String
name)> templateFfiAnnotationMissing = const Template<
Message Function(String name)> templateFfiFieldAnnotation = const Template<
Message Function(String name)>(
messageTemplate:
r"""Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi structs (Pointer<Void>) cannot have regular Dart fields.""",
withArguments: _withArgumentsFfiFieldAnnotation);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeFfiFieldAnnotation =
const Code<Message Function(String name)>(
"FfiFieldAnnotation",
templateFfiFieldAnnotation,
);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsFfiFieldAnnotation(String name) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeFfiFieldAnnotation,
message:
"""Field '${name}' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi structs (Pointer<Void>) cannot have regular Dart fields.""",
arguments: {'name': name});
}

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(String name)> templateFfiFieldInitializer = const Template<
Message Function(String name)>(
messageTemplate:
r"""Field '#name' is a dart:ffi Pointer to a struct field and therefore cannot be initialized before constructor execution.""",
withArguments: _withArgumentsFfiFieldInitializer);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeFfiFieldInitializer =
const Code<Message Function(String name)>(
"FfiFieldInitializer",
templateFfiFieldInitializer,
);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsFfiFieldInitializer(String name) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeFfiFieldInitializer,
message:
"""Field '${name}' is a dart:ffi Pointer to a struct field and therefore cannot be initialized before constructor execution.""",
arguments: {'name': name});
}

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(String name)> templateFfiNotStatic = const Template<
Message Function(String name)>(
messageTemplate:
r"""#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""",
withArguments: _withArgumentsFfiNotStatic);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeFfiNotStatic =
const Code<Message Function(String name)>(
"FfiNotStatic",
templateFfiNotStatic,
);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsFfiNotStatic(String name) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeFfiNotStatic,
message:
"""${name} expects a static function as parameter. dart:ffi only supports calling static Dart functions from c.""",
arguments: {'name': name});
}

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(String name)> templateFfiStructAnnotation = const Template<
Message Function(String name)>(
messageTemplate:
r"""Field '#name' is missing an annotation to declare its C++ type,dart:ffi structs (Pointer<Void>) cannot have regular Dart fields.""",
withArguments: _withArgumentsFfiAnnotationMissing);
r"""Class '#name' is a dart:ffi Pointer but has no struct annotation. Only struct Pointers can have fields.""",
withArguments: _withArgumentsFfiStructAnnotation);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name)> codeFfiAnnotationMissing =
const Code<Message Function(String name)> codeFfiStructAnnotation =
const Code<Message Function(String name)>(
"FfiAnnotationMissing",
templateFfiAnnotationMissing,
"FfiStructAnnotation",
templateFfiStructAnnotation,
);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsFfiAnnotationMissing(String name) {
Message _withArgumentsFfiStructAnnotation(String name) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeFfiAnnotationMissing,
return new Message(codeFfiStructAnnotation,
message:
"""Field '${name}' is missing an annotation to declare its C++ type,dart:ffi structs (Pointer<Void>) cannot have regular Dart fields.""",
"""Class '${name}' is a dart:ffi Pointer but has no struct annotation. Only struct Pointers can have fields.""",
arguments: {'name': name});
}

@@ -3378,7 +3451,7 @@ const Template<
Message Function(DartType _type)> templateFfiTypeInvalid = const Template<
Message Function(DartType _type)>(
messageTemplate:
r"""Expected type '#type' to be a valid and instantiated subtype of '_NativeType'.""",
r"""Expected type '#type' to be a valid and instantiated subtype of 'NativeType'.""",
withArguments: _withArgumentsFfiTypeInvalid);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3395,7 +3468,7 @@ Message _withArgumentsFfiTypeInvalid(DartType _type) {
String type = typeParts.join();
return new Message(codeFfiTypeInvalid,
message:
"""Expected type '${type}' to be a valid and instantiated subtype of '_NativeType'.""" +
"""Expected type '${type}' to be a valid and instantiated subtype of 'NativeType'.""" +
labeler.originMessages,
arguments: {'type': _type});
}
@@ -3442,29 +3515,29 @@ const Template<
Message Function(
String name,
DartType
_type)> templateFfiTypeOpaque = const Template<
_type)> templateFfiTypeUnsized = const Template<
Message Function(String name, DartType _type)>(
messageTemplate:
r"""Method '#name' cannot be called on something of type '#type' as this type is opaque.""",
withArguments: _withArgumentsFfiTypeOpaque);
r"""Method '#name' cannot be called on something of type '#type' as this type is unsized.""",
withArguments: _withArgumentsFfiTypeUnsized);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String name, DartType _type)> codeFfiTypeOpaque =
const Code<Message Function(String name, DartType _type)> codeFfiTypeUnsized =
const Code<Message Function(String name, DartType _type)>(
"FfiTypeOpaque",
templateFfiTypeOpaque,
"FfiTypeUnsized",
templateFfiTypeUnsized,
);

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsFfiTypeOpaque(String name, DartType _type) {
Message _withArgumentsFfiTypeUnsized(String name, DartType _type) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
TypeLabeler labeler = new TypeLabeler();
List<Object> typeParts = labeler.labelType(_type);
String type = typeParts.join();
return new Message(codeFfiTypeOpaque,
return new Message(codeFfiTypeUnsized,
message:
"""Method '${name}' cannot be called on something of type '${type}' as this type is opaque.""" +
"""Method '${name}' cannot be called on something of type '${type}' as this type is unsized.""" +
labeler.originMessages,
arguments: {'name': name, 'type': _type});
}
@@ -554,6 +554,7 @@ class KernelTarget extends TargetImplementation {
"dart:_internal",
"dart:async",
"dart:core",
"dart:ffi",
"dart:mirrors"
]) {
Uri uri = Uri.parse(platformLibrary);
@@ -569,8 +570,8 @@ class KernelTarget extends TargetImplementation {
break;
}
}
if (!found && uri.path != "mirrors") {
// dart:mirrors is optional.
if (!found && uri.path != "mirrors" && uri.path != "ffi") {
// dart:mirrors and dart:ffi are optional.
throw "Can't find $uri";
}
} else {
@@ -173,10 +173,13 @@ FastaUsageLong/analyzerCode: Fail
FastaUsageLong/example: Fail
FastaUsageShort/analyzerCode: Fail
FastaUsageShort/example: Fail
FfiAnnotationMissing/analyzerCode : Fail
FfiFieldAnnotation/analyzerCode: Fail
FfiFieldInitializer/analyzerCode: Fail
FfiNotStatic/analyzerCode: Fail
FfiStructAnnotation/analyzerCode: Fail
FfiTypeInvalid/analyzerCode: Fail
FfiTypeMismatch/analyzerCode: Fail
FfiTypeOpaque/analyzerCode: Fail
FfiTypeUnsized/analyzerCode: Fail
FieldInitializedOutsideDeclaringClass/script1: Fail
FieldInitializerOutsideConstructor/script1: Fail
FinalAndCovariant/script2: Fail
@@ -3434,15 +3434,30 @@ FfiTypeMismatch:

FfiTypeInvalid:
# Used by dart:ffi
template: "Expected type '#type' to be a valid and instantiated subtype of '_NativeType'."
template: "Expected type '#type' to be a valid and instantiated subtype of 'NativeType'."
external: test/ffi_test.dart

FfiTypeOpaque:
FfiTypeUnsized:
# Used by dart:ffi
template: "Method '#name' cannot be called on something of type '#type' as this type is opaque."
template: "Method '#name' cannot be called on something of type '#type' as this type is unsized."
external: test/ffi_test.dart

FfiAnnotationMissing:
FfiFieldAnnotation:
# Used by dart:ffi
template: "Field '#name' is missing an annotation to declare its C++ type,dart:ffi structs (Pointer<Void>) cannot have regular Dart fields."
template: "Field '#name' requires exactly one annotation to declare its C++ type, which cannot be Void. dart:ffi structs (Pointer<Void>) cannot have regular Dart fields."
external: test/ffi_test.dart

FfiNotStatic:
# Used by dart:ffi
template: "#name expects a static function as parameter. dart:ffi only supports calling static Dart functions from c."
external: test/ffi_test.dart

FfiFieldInitializer:
# Used by dart:ffi
template: "Field '#name' is a dart:ffi Pointer to a struct field and therefore cannot be initialized before constructor execution."
external: test/ffi_test.dart

FfiStructAnnotation:
# Used by dart:ffi
template: "Class '#name' is a dart:ffi Pointer but has no struct annotation. Only struct Pointers can have fields."
external: test/ffi_test.dart
@@ -155,6 +155,8 @@ abstract class TreeNode extends Node {

Component get enclosingComponent => parent?.enclosingComponent;

Library get enclosingLibrary => parent?.enclosingLibrary;

/// Returns the best known source location of the given AST node, or `null` if
/// the node is orphaned.
///
@@ -466,6 +468,8 @@ class Library extends NamedNode implements Comparable<Library>, FileUriNode {
Location _getLocationInEnclosingFile(int offset) {
return _getLocationInComponent(enclosingComponent, fileUri, offset);
}

Library get enclosingLibraray => this;
}

/// An import or export declaration in a library.

0 comments on commit 7d46d4b

Please sign in to comment.
You can’t perform that action at this time.