395e5f6037
I added TODOs for removing the old code after the constants update has landed. Change-Id: Icde8d68e4e7c4b51e9536f09ce4e514e3b00336d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98661 Auto-Submit: Daco Harkes <dacoharkes@google.com> Reviewed-by: Kevin Millikin <kmillikin@google.com>
208 lines
6.8 KiB
Dart
208 lines
6.8 KiB
Dart
// Copyright (c) 2019, 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.
|
|
|
|
// This file contains logic which is shared between the ffi_definition and
|
|
// ffi_use_site transformers.
|
|
|
|
library vm.transformations.ffi;
|
|
|
|
import 'package:kernel/ast.dart';
|
|
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
|
|
import 'package:kernel/core_types.dart';
|
|
import 'package:kernel/library_index.dart' show LibraryIndex;
|
|
import 'package:kernel/target/targets.dart' show DiagnosticReporter;
|
|
import 'package:kernel/type_environment.dart' show TypeEnvironment;
|
|
|
|
/// Represents the (instantiated) ffi.NativeType.
|
|
enum NativeType {
|
|
kPointer,
|
|
kNativeFunction,
|
|
kInt8,
|
|
kInt16,
|
|
kInt32,
|
|
kInt64,
|
|
kUint8,
|
|
kUint16,
|
|
kUint32,
|
|
kUnit64,
|
|
kIntptr,
|
|
kFloat,
|
|
kDouble,
|
|
kVoid
|
|
}
|
|
|
|
const NativeType kNativeTypeIntStart = NativeType.kInt8;
|
|
const NativeType kNativeTypeIntEnd = NativeType.kIntptr;
|
|
|
|
/// The [NativeType] class names, indexed by [NativeType].
|
|
const List<String> nativeTypeClassNames = [
|
|
'Pointer',
|
|
'NativeFunction',
|
|
'Int8',
|
|
'Int16',
|
|
'Int32',
|
|
'Int64',
|
|
'Uint8',
|
|
'Uint16',
|
|
'Uint32',
|
|
'Uint64',
|
|
'IntPtr',
|
|
'Float',
|
|
'Double',
|
|
'Void'
|
|
];
|
|
|
|
const int UNKNOWN = 0;
|
|
const int WORD_SIZE = -1;
|
|
|
|
/// The [NativeType] sizes in bytes, indexed by [NativeType].
|
|
const List<int> nativeTypeSizes = [
|
|
WORD_SIZE, // Pointer
|
|
UNKNOWN, // NativeFunction
|
|
1, // Int8
|
|
2, // Int16
|
|
4, // Int32
|
|
8, // Int64
|
|
1, // Uint8
|
|
2, // Uint16
|
|
4, // Uint32
|
|
8, // Uint64
|
|
WORD_SIZE, // IntPtr
|
|
4, // Float
|
|
8, // Double
|
|
UNKNOWN, // Void
|
|
];
|
|
|
|
/// [FfiTransformer] contains logic which is shared between
|
|
/// _FfiUseSiteTransformer and _FfiDefinitionTransformer.
|
|
class FfiTransformer extends Transformer {
|
|
final TypeEnvironment env;
|
|
final LibraryIndex index;
|
|
final ClassHierarchy hierarchy;
|
|
final DiagnosticReporter diagnosticReporter;
|
|
|
|
final Class intClass;
|
|
final Class doubleClass;
|
|
final Constructor pragmaConstructor;
|
|
|
|
final Library ffiLibrary;
|
|
final Class nativeFunctionClass;
|
|
final Class pointerClass;
|
|
final Class structClass;
|
|
final Procedure castMethod;
|
|
final Procedure loadMethod;
|
|
final Procedure storeMethod;
|
|
final Procedure offsetByMethod;
|
|
final Procedure asFunctionMethod;
|
|
final Procedure lookupFunctionMethod;
|
|
final Procedure fromFunctionMethod;
|
|
final Field structField;
|
|
|
|
/// Classes corresponding to [NativeType], indexed by [NativeType].
|
|
final List<Class> nativeTypesClasses;
|
|
|
|
FfiTransformer(
|
|
this.index, CoreTypes coreTypes, this.hierarchy, this.diagnosticReporter)
|
|
: env = new TypeEnvironment(coreTypes, hierarchy),
|
|
intClass = coreTypes.intClass,
|
|
doubleClass = coreTypes.doubleClass,
|
|
pragmaConstructor = coreTypes.pragmaConstructor,
|
|
ffiLibrary = index.getLibrary('dart:ffi'),
|
|
nativeFunctionClass = index.getClass('dart:ffi', 'NativeFunction'),
|
|
pointerClass = index.getClass('dart:ffi', 'Pointer'),
|
|
structClass = index.getClass('dart:ffi', 'Struct'),
|
|
castMethod = index.getMember('dart:ffi', 'Pointer', 'cast'),
|
|
loadMethod = index.getMember('dart:ffi', 'Pointer', 'load'),
|
|
storeMethod = index.getMember('dart:ffi', 'Pointer', 'store'),
|
|
offsetByMethod = index.getMember('dart:ffi', 'Pointer', 'offsetBy'),
|
|
asFunctionMethod = index.getMember('dart:ffi', 'Pointer', 'asFunction'),
|
|
lookupFunctionMethod =
|
|
index.getMember('dart:ffi', 'DynamicLibrary', 'lookupFunction'),
|
|
fromFunctionMethod =
|
|
index.getTopLevelMember('dart:ffi', 'fromFunction'),
|
|
structField = index.getTopLevelMember('dart:ffi', 'struct'),
|
|
nativeTypesClasses = nativeTypeClassNames
|
|
.map((name) => index.getClass('dart:ffi', name))
|
|
.toList() {}
|
|
|
|
/// Computes the Dart type corresponding to a ffi.[NativeType], returns null
|
|
/// if it is not a valid NativeType.
|
|
///
|
|
/// [Int8] -> [int]
|
|
/// [Int16] -> [int]
|
|
/// [Int32] -> [int]
|
|
/// [Int64] -> [int]
|
|
/// [Uint8] -> [int]
|
|
/// [Uint16] -> [int]
|
|
/// [Uint32] -> [int]
|
|
/// [Uint64] -> [int]
|
|
/// [IntPtr] -> [int]
|
|
/// [Double] -> [double]
|
|
/// [Float] -> [double]
|
|
/// [Void] -> [void]
|
|
/// [Pointer]<T> -> [Pointer]<T>
|
|
/// T extends [Pointer] -> T
|
|
/// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
|
|
/// where DartRepresentationOf(Tn) -> Sn
|
|
DartType convertNativeTypeToDartType(DartType nativeType) {
|
|
if (nativeType is! InterfaceType) {
|
|
return null;
|
|
}
|
|
Class nativeClass = (nativeType as InterfaceType).classNode;
|
|
if (env.isSubtypeOf(
|
|
InterfaceType(nativeClass), InterfaceType(pointerClass))) {
|
|
return nativeType;
|
|
}
|
|
NativeType nativeType_ = getType(nativeClass);
|
|
if (nativeType_ == null) {
|
|
return null;
|
|
}
|
|
if (kNativeTypeIntStart.index <= nativeType_.index &&
|
|
nativeType_.index <= kNativeTypeIntEnd.index) {
|
|
return InterfaceType(intClass);
|
|
}
|
|
if (nativeType_ == NativeType.kFloat || nativeType_ == NativeType.kDouble) {
|
|
return InterfaceType(doubleClass);
|
|
}
|
|
if (nativeType_ == NativeType.kVoid) {
|
|
return VoidType();
|
|
}
|
|
if (nativeType_ == NativeType.kNativeFunction) {
|
|
DartType fun = (nativeType as InterfaceType).typeArguments[0];
|
|
if (fun is FunctionType) {
|
|
if (fun.namedParameters.isNotEmpty) return null;
|
|
if (fun.positionalParameters.length != fun.requiredParameterCount)
|
|
return null;
|
|
if (fun.typeParameters.length != 0) return null;
|
|
DartType returnType = convertNativeTypeToDartType(fun.returnType);
|
|
if (returnType == null) return null;
|
|
List<DartType> argumentTypes = fun.positionalParameters
|
|
.map(this.convertNativeTypeToDartType)
|
|
.toList();
|
|
if (argumentTypes.contains(null)) return null;
|
|
return FunctionType(argumentTypes, returnType);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
NativeType getType(Class c) {
|
|
int index = nativeTypesClasses.indexOf(c);
|
|
if (index == -1) {
|
|
return null;
|
|
}
|
|
return NativeType.values[index];
|
|
}
|
|
}
|
|
|
|
/// Contains replaced members, of which all the call sites need to be replaced.
|
|
///
|
|
/// [ReplacedMembers] is populated by _FfiDefinitionTransformer and consumed by
|
|
/// _FfiUseSiteTransformer.
|
|
class ReplacedMembers {
|
|
final Map<Field, Procedure> replacedGetters;
|
|
final Map<Field, Procedure> replacedSetters;
|
|
ReplacedMembers(this.replacedGetters, this.replacedSetters);
|
|
}
|