Skip to content

Commit 6838266

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dyn_modules] Initial support for FFI calls in the interpreter
Limitations: * Compounds (structs, unions, arrays) are not supported yet. * Only x64 and arm64 are supported. TEST=ci Change-Id: I2929d514dc49015369d29dad31f479c661161655 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446282 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent 2aea88f commit 6838266

21 files changed

+1814
-1261
lines changed

pkg/dart2bytecode/docs/bytecode.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,10 @@ type ConstantDynamicCall extends ConstantPoolEntry {
801801
type ConstantExternalCall extends ConstantPoolEntry {
802802
Byte tag = 15;
803803
}
804+
805+
type ConstantFfiCall extends ConstantPoolEntry {
806+
Byte tag = 16;
807+
}
804808
```
805809

806810
### Exceptions table
@@ -1267,6 +1271,11 @@ arguments descriptor.
12671271
Invoke body of an external method.
12681272
ContantPool[D] is a ConstantExternalCall.
12691273

1274+
#### FfiCall D
1275+
1276+
Invoke native target of FFI call.
1277+
ContantPool[D] is a ConstantFfiCall.
1278+
12701279
#### ReturnTOS
12711280

12721281
Return to the caller using SP[0] as a result.

pkg/dart2bytecode/lib/assembler.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,11 @@ class BytecodeAssembler {
558558
_emitInstructionD(Opcode.kExternalCall, rd);
559559
}
560560

561+
@pragma('vm:prefer-inline')
562+
void emitFfiCall(int rd) {
563+
_emitInstructionD(Opcode.kFfiCall, rd);
564+
}
565+
561566
@pragma('vm:prefer-inline')
562567
void emitLoadStatic(int rd) {
563568
_emitInstructionD(Opcode.kLoadStatic, rd);

pkg/dart2bytecode/lib/bytecode_generator.dart

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class BytecodeGenerator extends RecursiveVisitor {
104104
final PragmaAnnotationParser pragmaParser;
105105
final RecognizedMethods recognizedMethods;
106106
final Map<Uri, Source> astUriToSource;
107+
final LibraryIndex ffiLibraryIndex;
107108
late StringTable stringTable;
108109
late ObjectTable objectTable;
109110
late Component bytecodeComponent;
@@ -164,7 +165,8 @@ class BytecodeGenerator extends RecursiveVisitor {
164165
this.pragmaParser,
165166
this.staticTypeContext)
166167
: recognizedMethods = new RecognizedMethods(staticTypeContext),
167-
astUriToSource = component.uriToSource {
168+
astUriToSource = component.uriToSource,
169+
ffiLibraryIndex = LibraryIndex(component, const ['dart:ffi']) {
168170
bytecodeComponent = new Component(coreTypes);
169171
stringTable = bytecodeComponent.stringTable;
170172
objectTable = bytecodeComponent.objectTable;
@@ -596,6 +598,11 @@ class BytecodeGenerator extends RecursiveVisitor {
596598
if (member.isExternal) {
597599
final String? externalName = getExternalName(coreTypes, member);
598600
if (externalName == null) {
601+
if (pragmaParser
602+
.parsedPragmas<ParsedFfiNativePragma>(member.annotations)
603+
.isNotEmpty) {
604+
flags |= FunctionDeclaration.isNativeFlag;
605+
}
599606
flags |= FunctionDeclaration.isExternalFlag;
600607
} else {
601608
flags |= FunctionDeclaration.isNativeFlag;
@@ -741,6 +748,10 @@ class BytecodeGenerator extends RecursiveVisitor {
741748
if (node.isExternal) {
742749
if (getExternalName(coreTypes, node) != null) {
743750
_genExternalCall(node);
751+
} else if (pragmaParser
752+
.parsedPragmas<ParsedFfiNativePragma>(node.annotations)
753+
.isNotEmpty) {
754+
_generateFfiCall(null);
744755
} else {
745756
_genNoSuchMethodForExternal(node);
746757
}
@@ -839,6 +850,21 @@ class BytecodeGenerator extends RecursiveVisitor {
839850
asm.emitExternalCall(externalCallCpIndex);
840851
}
841852

853+
void _generateFfiCall(Expression? target) {
854+
final function = enclosingFunction!;
855+
for (var param in function.positionalParameters) {
856+
asm.emitPush(locals.getVarIndexInFrame(param));
857+
}
858+
for (var param in locals.originalNamedParameters) {
859+
asm.emitPush(locals.getVarIndexInFrame(param));
860+
}
861+
if (target != null) {
862+
_generateNode(target);
863+
}
864+
final ffiCallCpIndex = cp.addFfiCall();
865+
asm.emitFfiCall(ffiCallCpIndex);
866+
}
867+
842868
LibraryIndex get libraryIndex => coreTypes.index;
843869

844870
late Procedure growableListLiteral =
@@ -976,7 +1002,11 @@ class BytecodeGenerator extends RecursiveVisitor {
9761002
late Field syncStarIteratorYieldStarIterable = libraryIndex.getField(
9771003
'dart:async', '_SyncStarIterator', '_yieldStarIterable');
9781004

979-
late Library? dartFfiLibrary = libraryIndex.tryGetLibrary('dart:ffi');
1005+
late Library? dartFfiLibrary = ffiLibraryIndex.tryGetLibrary('dart:ffi');
1006+
1007+
late Procedure? ffiCall = (dartFfiLibrary != null)
1008+
? ffiLibraryIndex.getTopLevelProcedure('dart:ffi', '_ffiCall')
1009+
: null;
9801010

9811011
// Selector for implicit dynamic calls 'foo(...)' where
9821012
// variable 'foo' has type 'dynamic'.
@@ -3436,6 +3466,10 @@ class BytecodeGenerator extends RecursiveVisitor {
34363466
// Skip over AST of the argument, return null.
34373467
asm.emitPushNull();
34383468
return;
3469+
} else if (target == ffiCall) {
3470+
assert(args.named.isEmpty);
3471+
_generateFfiCall(args.positional.single);
3472+
return;
34393473
}
34403474
if (target.isFactory) {
34413475
final constructedClass = target.enclosingClass!;

pkg/dart2bytecode/lib/constant_pool.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum ConstantTag {
3131
kInstantiatedInterfaceCall,
3232
kDynamicCall,
3333
kExternalCall,
34+
kFfiCall,
3435
}
3536

3637
String constantTagToString(ConstantTag tag) =>
@@ -87,6 +88,8 @@ abstract class ConstantPoolEntry {
8788
return new ConstantDynamicCall.read(reader);
8889
case ConstantTag.kExternalCall:
8990
return new ConstantExternalCall.read(reader);
91+
case ConstantTag.kFfiCall:
92+
return new ConstantFfiCall.read(reader);
9093
}
9194
throw 'Unexpected constant tag $tag';
9295
}
@@ -530,6 +533,29 @@ class ConstantExternalCall extends ConstantPoolEntry {
530533
bool operator ==(other) => identical(this, other);
531534
}
532535

536+
class ConstantFfiCall extends ConstantPoolEntry {
537+
ConstantFfiCall();
538+
539+
@override
540+
ConstantTag get tag => ConstantTag.kFfiCall;
541+
542+
@override
543+
void writeValue(BufferedWriter writer) {}
544+
545+
ConstantFfiCall.read(BufferedReader reader);
546+
547+
@override
548+
String toString() => 'FfiCall';
549+
550+
// Do not merge ConstantFfiCall entries.
551+
552+
@override
553+
int get hashCode => identityHashCode(this);
554+
555+
@override
556+
bool operator ==(other) => identical(this, other);
557+
}
558+
533559
/// Reserved constant pool entry.
534560
class _ReservedConstantPoolEntry extends ConstantPoolEntry {
535561
const _ReservedConstantPoolEntry();
@@ -607,6 +633,8 @@ class ConstantPool {
607633

608634
int addExternalCall() => _add(ConstantExternalCall());
609635

636+
int addFfiCall() => _add(ConstantFfiCall());
637+
610638
int addStaticField(Field field) =>
611639
_add(new ConstantStaticField(objectTable.getHandle(field)!));
612640

pkg/dart2bytecode/lib/dbc.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ enum Opcode {
213213
kAllocateRecord_Wide,
214214
kLoadRecordField,
215215
kLoadRecordField_Wide,
216+
217+
// FFI
218+
kFfiCall,
219+
kFfiCall_Wide,
216220
}
217221

218222
/// Compact variants of opcodes are always even.
@@ -464,6 +468,8 @@ const Map<Opcode, Format> BytecodeFormats = const {
464468
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
465469
Opcode.kLoadRecordField: const Format(
466470
Encoding.kD, const [Operand.imm, Operand.none, Operand.none]),
471+
Opcode.kFfiCall: const Format(
472+
Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
467473
};
468474

469475
// Should match constant in runtime/vm/stack_frame_kbc.h.

pkg/vm/lib/transformations/pragma.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const kVmDisableUnboxedParametersPragmaName = "vm:disable-unboxed-parameters";
1616
const kVmKeepNamePragmaName = "vm:keep-name";
1717
const kVmPlatformConstPragmaName = "vm:platform-const";
1818
const kVmPlatformConstIfPragmaName = "vm:platform-const-if";
19+
const kVmFfiNative = "vm:ffi:native";
1920

2021
// Pragmas recognized by dart2wasm
2122
const kWasmEntryPointPragmaName = "wasm:entry-point";
@@ -81,6 +82,10 @@ class ParsedPlatformConstPragma implements ParsedPragma {
8182
const ParsedPlatformConstPragma();
8283
}
8384

85+
class ParsedFfiNativePragma implements ParsedPragma {
86+
const ParsedFfiNativePragma();
87+
}
88+
8489
class ParsedDynModuleEntryPointPragma implements ParsedPragma {
8590
const ParsedDynModuleEntryPointPragma();
8691
}
@@ -206,6 +211,8 @@ class ConstantPragmaAnnotationParser implements PragmaAnnotationParser {
206211
"pragma: $options";
207212
}
208213
return options.value ? const ParsedPlatformConstPragma() : null;
214+
case kVmFfiNative:
215+
return const ParsedFfiNativePragma();
209216
case kWasmEntryPointPragmaName:
210217
return const ParsedEntryPointPragma(PragmaEntryPointType.Default);
211218
case kWasmExportPragmaName:

runtime/vm/BUILD.gn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ source_set("libprotozero") {
166166
}
167167

168168
public_configs = [ ":libprotozero_config" ]
169-
deps = [ "$perfetto_root_path/src/protozero:protozero" ]
169+
deps = [ "$perfetto_root_path/src/protozero" ]
170170
}
171171

172172
library_for_all_configs("libdart_vm") {
@@ -210,7 +210,7 @@ library_for_all_configs("libdart_vm") {
210210
sources += [ "thread_interrupter_android_arm.S" ]
211211
}
212212
if (!is_win) {
213-
sources += [ "simulator_arm64_trampolines.S" ]
213+
sources += [ "ffi_trampolines_arm64.S" ]
214214
}
215215
include_dirs = [ ".." ]
216216
}

runtime/vm/bytecode_reader.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ intptr_t BytecodeReaderHelper::ReadConstantPool(const Function& function,
522522
kInstantiatedInterfaceCall,
523523
kDynamicCall,
524524
kExternalCall,
525+
kFfiCall,
525526
};
526527

527528
Object& obj = Object::Handle(Z);
@@ -691,6 +692,14 @@ intptr_t BytecodeReaderHelper::ReadConstantPool(const Function& function,
691692
pool.SetRawValueAt(i, 0);
692693
continue;
693694
}
695+
case ConstantPoolTag::kFfiCall: {
696+
// FfiCall constant has 1 raw value entry.
697+
pool.SetTypeAt(i, ObjectPool::EntryType::kNativeFunction,
698+
ObjectPool::Patchability::kNotPatchable,
699+
ObjectPool::SnapshotBehavior::kNotSnapshotable);
700+
pool.SetRawValueAt(i, 0);
701+
continue;
702+
}
694703
default:
695704
UNREACHABLE();
696705
}
@@ -2107,7 +2116,9 @@ void BytecodeReaderHelper::ReadFunctionDeclarations(const Class& cls) {
21072116

21082117
if (is_native) {
21092118
name ^= ReadObject();
2110-
function.set_native_name(name);
2119+
if (!name.IsNull()) {
2120+
function.set_native_name(name);
2121+
}
21112122
}
21122123

21132124
if ((flags & kIsAbstractFlag) == 0) {

0 commit comments

Comments
 (0)