Version 2.14.0-89.0.dev
Merge commit 'f53af0d445c8f73562274bcea9e0bec394a1f6a0' into 'dev'
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect b/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect
index cad4e7a..cdeb1e9 100644
--- a/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/ffi_sample.dart.weak.transformed.expect
@@ -30,18 +30,20 @@
abstract member-signature method toString() → core::String*; -> core::Object::toString
abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+ @#C11
get x() → core::double*
- return ffi::_loadDouble(this.{ffi::_Compound::_typedDataBase}, (#C12).{core::List::[]}(ffi::_abi()));
+ return ffi::_loadDouble(this.{ffi::_Compound::_typedDataBase}, (#C13).{core::List::[]}(ffi::_abi()));
set x(core::double* #v) → void
- return ffi::_storeDouble(this.{ffi::_Compound::_typedDataBase}, (#C12).{core::List::[]}(ffi::_abi()), #v);
+ return ffi::_storeDouble(this.{ffi::_Compound::_typedDataBase}, (#C13).{core::List::[]}(ffi::_abi()), #v);
+ @#C11
get y() → core::double*
- return ffi::_loadDouble(this.{ffi::_Compound::_typedDataBase}, (#C14).{core::List::[]}(ffi::_abi()));
+ return ffi::_loadDouble(this.{ffi::_Compound::_typedDataBase}, (#C15).{core::List::[]}(ffi::_abi()));
set y(core::double* #v) → void
- return ffi::_storeDouble(this.{ffi::_Compound::_typedDataBase}, (#C14).{core::List::[]}(ffi::_abi()), #v);
+ return ffi::_storeDouble(this.{ffi::_Compound::_typedDataBase}, (#C15).{core::List::[]}(ffi::_abi()), #v);
get next() → ffi::Pointer<self::Coordinate*>*
- return ffi::_fromAddress<self::Coordinate*>(ffi::_loadIntPtr(this.{ffi::_Compound::_typedDataBase}, (#C16).{core::List::[]}(ffi::_abi())));
+ return ffi::_fromAddress<self::Coordinate*>(ffi::_loadIntPtr(this.{ffi::_Compound::_typedDataBase}, (#C17).{core::List::[]}(ffi::_abi())));
set next(ffi::Pointer<self::Coordinate*>* #v) → void
- return ffi::_storeIntPtr(this.{ffi::_Compound::_typedDataBase}, (#C16).{core::List::[]}(ffi::_abi()), #v.{ffi::Pointer::address});
+ return ffi::_storeIntPtr(this.{ffi::_Compound::_typedDataBase}, (#C17).{core::List::[]}(ffi::_abi()), #v.{ffi::Pointer::address});
}
static method main() → dynamic {}
@@ -56,12 +58,13 @@
#C8 = 24
#C9 = 20
#C10 = <core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <core::int*>[#C15, #C15, #C15]
+ #C11 = ffi::Double {}
+ #C12 = 0
+ #C13 = <core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/front_end/testcases/incremental.status b/pkg/front_end/testcases/incremental.status
index 57a86f3..afed71c 100644
--- a/pkg/front_end/testcases/incremental.status
+++ b/pkg/front_end/testcases/incremental.status
@@ -6,7 +6,3 @@
# http://dartbug.com/41812#issuecomment-684825703
strongmode_mixins_2: Crash
-
-# http://dartbug.com/45899
-crash_05: Crash
-crash_06: Crash
diff --git a/pkg/front_end/testcases/incremental/crash_05.yaml b/pkg/front_end/testcases/incremental/crash_05.yaml
index 405d4f2..58d324b 100644
--- a/pkg/front_end/testcases/incremental/crash_05.yaml
+++ b/pkg/front_end/testcases/incremental/crash_05.yaml
@@ -30,4 +30,4 @@
invalidate:
- main.dart
expectedLibraryCount: 2
- expectsRebuildBodiesOnly: true
\ No newline at end of file
+ expectsRebuildBodiesOnly: false
diff --git a/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect b/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect
new file mode 100644
index 0000000..7b59748
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/crash_05.yaml.world.2.expect
@@ -0,0 +1,62 @@
+main = <No Member>;
+library from "org-dartlang-test:///lib.dart" as lib {
+
+ import "dart:ffi";
+
+ @#C6
+ class Y extends dart.ffi::Struct {
+ static final field dart.core::int* #sizeOf = (#C8).{dart.core::List::[]}(dart.ffi::_abi())/*isLegacy*/;
+ synthetic constructor •() → lib::Y
+ : super dart.ffi::Struct::•()
+ ;
+ constructor #fromTypedDataBase(dart.core::Object #typedDataBase) → lib::Y
+ : super dart.ffi::Struct::_fromTypedDataBase(#typedDataBase)
+ ;
+ @#C9
+ get yy() → dart.core::int
+ return dart.ffi::_loadUint32(this.{dart.ffi::_Compound::_typedDataBase}, (#C11).{dart.core::List::[]}(dart.ffi::_abi()));
+ @#C9
+ set yy(dart.core::int #externalFieldValue) → void
+ return dart.ffi::_storeUint32(this.{dart.ffi::_Compound::_typedDataBase}, (#C11).{dart.core::List::[]}(dart.ffi::_abi()), #externalFieldValue);
+ }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+ import "dart:ffi";
+ import "org-dartlang-test:///lib.dart";
+
+ @#C15
+ class X extends dart.ffi::Struct {
+ static final field dart.core::int* #sizeOf = (#C8).{dart.core::List::[]}(dart.ffi::_abi())/*isLegacy*/;
+ synthetic constructor •() → main::X
+ : super dart.ffi::Struct::•()
+ ;
+ constructor #fromTypedDataBase(dart.core::Object #typedDataBase) → main::X
+ : super dart.ffi::Struct::_fromTypedDataBase(#typedDataBase)
+ ;
+ get xx() → lib::Y
+ return new lib::Y::#fromTypedDataBase( block {
+ dart.core::Object #typedDataBase = this.{dart.ffi::_Compound::_typedDataBase};
+ dart.core::int #offset = (#C11).{dart.core::List::[]}(dart.ffi::_abi());
+ } =>#typedDataBase is dart.ffi::Pointer<dynamic> ?{dart.core::Object} dart.ffi::_fromAddress<lib::Y>(#typedDataBase.{dart.ffi::Pointer::address}.{dart.core::num::+}(#offset)) : let dart.typed_data::TypedData #typedData = dart._internal::unsafeCast<dart.typed_data::TypedData>(#typedDataBase) in #typedData.{dart.typed_data::TypedData::buffer}.{dart.typed_data::ByteBuffer::asUint8List}(#typedData.{dart.typed_data::TypedData::offsetInBytes}.{dart.core::num::+}(#offset), (#C8).{dart.core::List::[]}(dart.ffi::_abi())));
+ set xx(lib::Y #externalFieldValue) → void
+ return dart.ffi::_memCopy(this.{dart.ffi::_Compound::_typedDataBase}, (#C11).{dart.core::List::[]}(dart.ffi::_abi()), #externalFieldValue.{dart.ffi::_Compound::_typedDataBase}, #C10, (#C8).{dart.core::List::[]}(dart.ffi::_abi()));
+ }
+}
+constants {
+ #C1 = "vm:ffi:struct-fields"
+ #C2 = TypeLiteralConstant(dart.ffi::Uint32)
+ #C3 = <dart.core::Type>[#C2]
+ #C4 = null
+ #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
+ #C6 = dart.core::pragma {name:#C1, options:#C5}
+ #C7 = 4
+ #C8 = <dart.core::int*>[#C7, #C7, #C7]
+ #C9 = dart.ffi::Uint32 {}
+ #C10 = 0
+ #C11 = <dart.core::int*>[#C10, #C10, #C10]
+ #C12 = TypeLiteralConstant(lib::Y)
+ #C13 = <dart.core::Type>[#C12]
+ #C14 = dart.ffi::_FfiStructLayout {fieldTypes:#C13, packing:#C4}
+ #C15 = dart.core::pragma {name:#C1, options:#C14}
+}
diff --git a/pkg/front_end/testcases/incremental/crash_06.yaml b/pkg/front_end/testcases/incremental/crash_06.yaml
index 932a44d..1c46cb0 100644
--- a/pkg/front_end/testcases/incremental/crash_06.yaml
+++ b/pkg/front_end/testcases/incremental/crash_06.yaml
@@ -7,6 +7,7 @@
type: newworld
worlds:
- entry: structs.dart
+ errors: true
experiments: non-nullable
sources:
structs.dart: |
@@ -20,11 +21,12 @@
expectedLibraryCount: 1
- entry: structs.dart
+ errors: true
experiments: non-nullable
worldType: updated
expectInitializeFromDill: false
invalidate:
- structs.dart
expectedLibraryCount: 1
- expectsRebuildBodiesOnly: true
+ expectsRebuildBodiesOnly: false
diff --git a/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect b/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect
new file mode 100644
index 0000000..2e6d138
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/crash_06.yaml.world.1.expect
@@ -0,0 +1,62 @@
+main = <No Member>;
+//
+// Problems in component:
+//
+// org-dartlang-test:///structs.dart:6:14: Error: Field 'zz' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs and Unions cannot have regular Dart fields.
+// external Z zz;
+// ^
+//
+library from "org-dartlang-test:///structs.dart" as str {
+//
+// Problems in library:
+//
+// org-dartlang-test:///structs.dart:6:12: Error: 'Z' isn't a type.
+// external Z zz;
+// ^
+//
+// org-dartlang-test:///structs.dart:6:12: Error: Type 'Z' not found.
+// external Z zz;
+// ^
+//
+
+ import "dart:ffi";
+
+ @#C6
+ class A extends dart.ffi::Struct {
+ static final field dart.core::int* #sizeOf = (#C8).{dart.core::List::[]}(dart.ffi::_abi())/*isLegacy*/;
+ synthetic constructor •() → str::A
+ : super dart.ffi::Struct::•()
+ ;
+ constructor #fromTypedDataBase(dart.core::Object #typedDataBase) → str::A
+ : super dart.ffi::Struct::_fromTypedDataBase(#typedDataBase)
+ ;
+ get yy() → str::Y
+ return new str::Y::#fromTypedDataBase( block {
+ dart.core::Object #typedDataBase = this.{dart.ffi::_Compound::_typedDataBase};
+ dart.core::int #offset = (#C8).{dart.core::List::[]}(dart.ffi::_abi());
+ } =>#typedDataBase is dart.ffi::Pointer<dynamic> ?{dart.core::Object} dart.ffi::_fromAddress<str::Y>(#typedDataBase.{dart.ffi::Pointer::address}.{dart.core::num::+}(#offset)) : let dart.typed_data::TypedData #typedData = dart._internal::unsafeCast<dart.typed_data::TypedData>(#typedDataBase) in #typedData.{dart.typed_data::TypedData::buffer}.{dart.typed_data::ByteBuffer::asUint8List}(#typedData.{dart.typed_data::TypedData::offsetInBytes}.{dart.core::num::+}(#offset), (#C8).{dart.core::List::[]}(dart.ffi::_abi())));
+ set yy(str::Y #externalFieldValue) → void
+ return dart.ffi::_memCopy(this.{dart.ffi::_Compound::_typedDataBase}, (#C8).{dart.core::List::[]}(dart.ffi::_abi()), #externalFieldValue.{dart.ffi::_Compound::_typedDataBase}, #C7, (#C8).{dart.core::List::[]}(dart.ffi::_abi()));
+ }
+ class Y extends dart.ffi::Struct {
+ static final field dart.core::int* #sizeOf = (#C8).{dart.core::List::[]}(dart.ffi::_abi())/*isLegacy*/;
+ synthetic constructor •() → str::Y
+ : super dart.ffi::Struct::•()
+ ;
+ constructor #fromTypedDataBase(dart.core::Object #typedDataBase) → str::Y
+ : super dart.ffi::Struct::_fromTypedDataBase(#typedDataBase)
+ ;
+ external get zz() → invalid-type;
+ external set zz(invalid-type #externalFieldValue) → void;
+ }
+}
+constants {
+ #C1 = "vm:ffi:struct-fields"
+ #C2 = TypeLiteralConstant(str::Y)
+ #C3 = <dart.core::Type>[#C2]
+ #C4 = null
+ #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
+ #C6 = dart.core::pragma {name:#C1, options:#C5}
+ #C7 = 0
+ #C8 = <dart.core::int*>[#C7, #C7, #C7]
+}
diff --git a/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect b/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect
new file mode 100644
index 0000000..2e6d138
--- /dev/null
+++ b/pkg/front_end/testcases/incremental/crash_06.yaml.world.2.expect
@@ -0,0 +1,62 @@
+main = <No Member>;
+//
+// Problems in component:
+//
+// org-dartlang-test:///structs.dart:6:14: Error: Field 'zz' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs and Unions cannot have regular Dart fields.
+// external Z zz;
+// ^
+//
+library from "org-dartlang-test:///structs.dart" as str {
+//
+// Problems in library:
+//
+// org-dartlang-test:///structs.dart:6:12: Error: 'Z' isn't a type.
+// external Z zz;
+// ^
+//
+// org-dartlang-test:///structs.dart:6:12: Error: Type 'Z' not found.
+// external Z zz;
+// ^
+//
+
+ import "dart:ffi";
+
+ @#C6
+ class A extends dart.ffi::Struct {
+ static final field dart.core::int* #sizeOf = (#C8).{dart.core::List::[]}(dart.ffi::_abi())/*isLegacy*/;
+ synthetic constructor •() → str::A
+ : super dart.ffi::Struct::•()
+ ;
+ constructor #fromTypedDataBase(dart.core::Object #typedDataBase) → str::A
+ : super dart.ffi::Struct::_fromTypedDataBase(#typedDataBase)
+ ;
+ get yy() → str::Y
+ return new str::Y::#fromTypedDataBase( block {
+ dart.core::Object #typedDataBase = this.{dart.ffi::_Compound::_typedDataBase};
+ dart.core::int #offset = (#C8).{dart.core::List::[]}(dart.ffi::_abi());
+ } =>#typedDataBase is dart.ffi::Pointer<dynamic> ?{dart.core::Object} dart.ffi::_fromAddress<str::Y>(#typedDataBase.{dart.ffi::Pointer::address}.{dart.core::num::+}(#offset)) : let dart.typed_data::TypedData #typedData = dart._internal::unsafeCast<dart.typed_data::TypedData>(#typedDataBase) in #typedData.{dart.typed_data::TypedData::buffer}.{dart.typed_data::ByteBuffer::asUint8List}(#typedData.{dart.typed_data::TypedData::offsetInBytes}.{dart.core::num::+}(#offset), (#C8).{dart.core::List::[]}(dart.ffi::_abi())));
+ set yy(str::Y #externalFieldValue) → void
+ return dart.ffi::_memCopy(this.{dart.ffi::_Compound::_typedDataBase}, (#C8).{dart.core::List::[]}(dart.ffi::_abi()), #externalFieldValue.{dart.ffi::_Compound::_typedDataBase}, #C7, (#C8).{dart.core::List::[]}(dart.ffi::_abi()));
+ }
+ class Y extends dart.ffi::Struct {
+ static final field dart.core::int* #sizeOf = (#C8).{dart.core::List::[]}(dart.ffi::_abi())/*isLegacy*/;
+ synthetic constructor •() → str::Y
+ : super dart.ffi::Struct::•()
+ ;
+ constructor #fromTypedDataBase(dart.core::Object #typedDataBase) → str::Y
+ : super dart.ffi::Struct::_fromTypedDataBase(#typedDataBase)
+ ;
+ external get zz() → invalid-type;
+ external set zz(invalid-type #externalFieldValue) → void;
+ }
+}
+constants {
+ #C1 = "vm:ffi:struct-fields"
+ #C2 = TypeLiteralConstant(str::Y)
+ #C3 = <dart.core::Type>[#C2]
+ #C4 = null
+ #C5 = dart.ffi::_FfiStructLayout {fieldTypes:#C3, packing:#C4}
+ #C6 = dart.core::pragma {name:#C1, options:#C5}
+ #C7 = 0
+ #C8 = <dart.core::int*>[#C7, #C7, #C7]
+}
diff --git a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect
index e983eec..481fe3f 100644
--- a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.1.expect
@@ -23,18 +23,20 @@
abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+ @#C11
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ @#C11
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -59,10 +61,11 @@
#C8 = 24
#C9 = 20
#C10 = <dart.core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <dart.core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <dart.core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C11 = dart.ffi::Double {}
+ #C12 = 0
+ #C13 = <dart.core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <dart.core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <dart.core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect
index f61ae87..751d0a9 100644
--- a/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/ffi_01.yaml.world.2.expect
@@ -23,18 +23,20 @@
abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+ @#C11
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ @#C11
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -63,10 +65,11 @@
#C8 = 24
#C9 = 20
#C10 = <dart.core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <dart.core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <dart.core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C11 = dart.ffi::Double {}
+ #C12 = 0
+ #C13 = <dart.core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <dart.core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <dart.core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect b/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect
index 1979d4a..deb8a44 100644
--- a/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/ffi_02.yaml.world.1.expect
@@ -23,18 +23,20 @@
abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+ @#C11
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ @#C11
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -60,10 +62,11 @@
#C8 = 24
#C9 = 20
#C10 = <dart.core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <dart.core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <dart.core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C11 = dart.ffi::Double {}
+ #C12 = 0
+ #C13 = <dart.core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <dart.core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <dart.core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect
index e983eec..481fe3f 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.1.expect
@@ -23,18 +23,20 @@
abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+ @#C11
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ @#C11
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -59,10 +61,11 @@
#C8 = 24
#C9 = 20
#C10 = <dart.core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <dart.core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <dart.core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C11 = dart.ffi::Double {}
+ #C12 = 0
+ #C13 = <dart.core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <dart.core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <dart.core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect
index aae1c15..aeab1b0 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.2.expect
@@ -23,18 +23,20 @@
abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+ @#C11
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ @#C11
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -60,10 +62,11 @@
#C8 = 24
#C9 = 20
#C10 = <dart.core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <dart.core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <dart.core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C11 = dart.ffi::Double {}
+ #C12 = 0
+ #C13 = <dart.core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <dart.core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <dart.core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect
index dcd9515..1c8bfde 100644
--- a/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect
+++ b/pkg/front_end/testcases/incremental/no_outline_change_35.yaml.world.3.expect
@@ -24,18 +24,20 @@
abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString
abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod
abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType
+ @#C11
get x() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()));
set x(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C12).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C13).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ @#C11
get y() → dart.core::double*
- return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()));
+ return dart.ffi::_loadDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()));
set y(dart.core::double* #v) → void
- return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C14).{dart.core::List::[]}(dart.ffi::_abi()), #v);
+ return dart.ffi::_storeDouble(this.{dart.ffi::_Compound::_typedDataBase}, (#C15).{dart.core::List::[]}(dart.ffi::_abi()), #v);
get next() → dart.ffi::Pointer<lib::Coordinate*>*
- return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi())));
+ return dart.ffi::_fromAddress<lib::Coordinate*>(dart.ffi::_loadIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi())));
set next(dart.ffi::Pointer<lib::Coordinate*>* #v) → void
- return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C16).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
+ return dart.ffi::_storeIntPtr(this.{dart.ffi::_Compound::_typedDataBase}, (#C17).{dart.core::List::[]}(dart.ffi::_abi()), #v.{dart.ffi::Pointer::address});
}
}
library from "org-dartlang-test:///main.dart" as main {
@@ -61,10 +63,11 @@
#C8 = 24
#C9 = 20
#C10 = <dart.core::int*>[#C8, #C9, #C8]
- #C11 = 0
- #C12 = <dart.core::int*>[#C11, #C11, #C11]
- #C13 = 8
- #C14 = <dart.core::int*>[#C13, #C13, #C13]
- #C15 = 16
- #C16 = <dart.core::int*>[#C15, #C15, #C15]
+ #C11 = dart.ffi::Double {}
+ #C12 = 0
+ #C13 = <dart.core::int*>[#C12, #C12, #C12]
+ #C14 = 8
+ #C15 = <dart.core::int*>[#C14, #C14, #C14]
+ #C16 = 16
+ #C17 = <dart.core::int*>[#C16, #C16, #C16]
}
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index b7ef1d7..e69b8a1 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -103,9 +103,9 @@
// Data structures for topological navigation.
Map<Class, IndexedClass> indexedCompoundClasses = {};
- Map<Class, Set<Class>> compoundClassDependencies = {};
- Map<Class, bool> fieldsValid = {};
- Map<Class, CompoundNativeTypeCfe> compoundCache = {};
+ Set<Class> transformCompounds = {};
+ Set<Class> transformCompoundsInvalid = {};
+ Map<Class, NativeTypeCfe> compoundCache = {};
ChangedStructureNotifier changedStructureNotifier;
@@ -121,9 +121,53 @@
: super(index, coreTypes, hierarchy, diagnosticReporter,
referenceFromIndex) {}
+ /// Finds all compound class dependencies.
+ ///
+ /// Works both for transformed and non-transformed compound classes.
+ Set<Class> _compoundClassDependencies(Class node) {
+ final dependencies = <Class>{};
+ final membersWithAnnotations =
+ _compoundFieldMembers(node, includeSetters: false);
+ for (final Member f in membersWithAnnotations) {
+ final type = _compoundMemberType(f);
+ if (isCompoundSubtype(type)) {
+ final clazz = (type as InterfaceType).classNode;
+ dependencies.add(clazz);
+ } else if (isArrayType(type)) {
+ final sizeAnnotations = _getArraySizeAnnotations(f);
+ if (sizeAnnotations.length == 1) {
+ final singleElementType = arraySingleElementType(type);
+ if (isCompoundSubtype(singleElementType)) {
+ final clazz = (singleElementType as InterfaceType).classNode;
+ dependencies.add(clazz);
+ }
+ }
+ }
+ }
+ return dependencies;
+ }
+
+ /// Creates a dependency graph containing all compounds being compiled
+ /// in this compilation, and their transitive dependencies.
+ CompoundDependencyGraph<Class> _compoundDependencyGraph() {
+ Map<Class, Set<Class>> compoundClassDependencies = {};
+ final toProcess = [...transformCompounds, ...transformCompoundsInvalid];
+
+ while (toProcess.isNotEmpty) {
+ final clazz = toProcess.removeLast();
+ if (!compoundClassDependencies.containsKey(clazz)) {
+ final dependencies = _compoundClassDependencies(clazz);
+ compoundClassDependencies[clazz] = dependencies;
+ toProcess.addAll(dependencies);
+ }
+ }
+
+ return CompoundDependencyGraph(compoundClassDependencies);
+ }
+
void manualVisitInTopologicalOrder() {
- final connectedComponents = computeStrongComponents(
- CompoundDependencyGraph(compoundClassDependencies));
+ final dependencyGraph = _compoundDependencyGraph();
+ final connectedComponents = computeStrongComponents(dependencyGraph);
connectedComponents.forEach((List<Class> component) {
bool report = false;
@@ -132,8 +176,7 @@
report = true;
}
if (component.length == 1) {
- if (compoundClassDependencies[component.single]
- .contains(component.single)) {
+ if (dependencyGraph.map[component.single].contains(component.single)) {
// Direct cycle.
report = true;
}
@@ -146,10 +189,31 @@
e.fileOffset,
e.name.length,
e.fileUri);
+ compoundCache[e] = InvalidNativeTypeCfe("Cyclic members.");
+ if (transformCompoundsInvalid.contains(e) ||
+ transformCompounds.contains(e)) {
+ final indexedClass = indexedCompoundClasses[e];
+ _addSizeOfField(e, indexedClass);
+ }
});
} else {
// Only visit the ones without cycles.
- visitClassInTopologicalOrder(component.single);
+ final clazz = component.single;
+ final compoundData = _findFields(clazz);
+ final compoundType = compoundData.compoundType;
+ compoundCache[clazz] = compoundType;
+ final indexedClass = indexedCompoundClasses[clazz];
+ if (transformCompounds.contains(clazz) &&
+ compoundType is! InvalidNativeTypeCfe) {
+ // Only visit if it has not been transformed yet, and its fields
+ // are valid.
+
+ _replaceFields(clazz, indexedClass, compoundData);
+ _addSizeOfField(clazz, indexedClass, compoundType.size);
+ changedStructureNotifier?.registerClassMemberChange(clazz);
+ } else if (transformCompoundsInvalid.contains(clazz)) {
+ _addSizeOfField(clazz, indexedClass);
+ }
}
});
}
@@ -166,12 +230,19 @@
return node;
}
- @override
- visitClass(Class node) {
+ bool _isUserCompound(Class node) {
if (!hierarchy.isSubclassOf(node, compoundClass) ||
node == compoundClass ||
node == structClass ||
node == unionClass) {
+ return false;
+ }
+ return true;
+ }
+
+ @override
+ visitClass(Class node) {
+ if (!_isUserCompound(node)) {
return node;
}
@@ -181,20 +252,17 @@
_checkConstructors(node, indexedClass);
indexedCompoundClasses[node] = indexedClass;
- fieldsValid[node] = _checkFieldAnnotations(node, packing);
+ final fieldsValid = _checkFieldAnnotations(node, packing);
+ if (fieldsValid) {
+ // Only do the transformation if the compound is valid.
+ transformCompounds.add(node);
+ } else {
+ transformCompoundsInvalid.add(node);
+ }
return node;
}
- void visitClassInTopologicalOrder(Class node) {
- final indexedClass = indexedCompoundClasses[node];
- if (fieldsValid[node]) {
- final compoundSize = _replaceFields(node, indexedClass);
- _replaceSizeOfMethod(node, compoundSize, indexedClass);
- changedStructureNotifier?.registerClassMemberChange(node);
- }
- }
-
/// Returns packing if any.
int _checkCompoundClass(Class node) {
if (node.typeParameters.length > 0) {
@@ -237,25 +305,39 @@
return null;
}
- /// Returns members of [node] that correspond to compound fields.
+ /// Returns members of [node] that possibly correspond to compound fields.
///
/// Note that getters and setters that originate from an external field have
/// the same `fileOffset`, we always returns getters first.
- List<Member> _compoundFieldMembers(Class node) {
- final externalGetterSetters = [...node.procedures]
- ..retainWhere((p) => p.isExternal && (p.isGetter || p.isSetter));
- final compoundMembers = [...node.fields, ...externalGetterSetters]
- ..sort((m1, m2) {
+ ///
+ /// This works for both transformed and non-transformed structs.
+ List<Member> _compoundFieldMembers(Class node,
+ {bool possiblyAlreadyTransformed = true, bool includeSetters = true}) {
+ final getterSetters = node.procedures.where((p) {
+ if (!possiblyAlreadyTransformed && !p.isExternal) {
+ // If a struct has not been transformed yet, we have the guarantee
+ // that getters and setters corresponding to native fields are external.
+ return false;
+ }
+ if (p.isSetter && includeSetters) {
+ return true;
+ }
+ return p.isGetter;
+ });
+ final compoundMembers = [...node.fields, ...getterSetters]..sort((m1, m2) {
if (m1.fileOffset == m2.fileOffset) {
// Getter and setter have same offset, getter comes first.
- return (m1 as Procedure).isGetter ? -1 : 1;
+ if (m1 is Procedure) {
+ return m1.isGetter ? -1 : 1;
+ }
+ // Generated fields with fileOffset identical to class, fallthrough.
}
return m1.fileOffset - m2.fileOffset;
});
return compoundMembers;
}
- DartType _compoundFieldMemberType(Member member) {
+ DartType _compoundMemberType(Member member) {
if (member is Field) {
return member.type;
}
@@ -268,9 +350,8 @@
bool _checkFieldAnnotations(Class node, int packing) {
bool success = true;
- compoundClassDependencies[node] = {};
- final membersWithAnnotations = _compoundFieldMembers(node)
- ..retainWhere((m) => (m is Field) || (m is Procedure && m.isGetter));
+ final membersWithAnnotations = _compoundFieldMembers(node,
+ possiblyAlreadyTransformed: false, includeSetters: false);
for (final Member f in membersWithAnnotations) {
if (f is Field) {
if (f.initializer is! NullLiteral) {
@@ -284,7 +365,7 @@
}
}
final nativeTypeAnnos = _getNativeTypeAnnotations(f).toList();
- final type = _compoundFieldMemberType(f);
+ final type = _compoundMemberType(f);
if (type is NullType) {
diagnosticReporter.report(
templateFfiFieldNull.withArguments(f.name.text),
@@ -307,7 +388,6 @@
}
if (isCompoundSubtype(type)) {
final clazz = (type as InterfaceType).classNode;
- compoundClassDependencies[node].add(clazz);
_checkPacking(node, packing, clazz, f);
} else if (isArrayType(type)) {
final sizeAnnotations = _getArraySizeAnnotations(f);
@@ -315,7 +395,6 @@
final singleElementType = arraySingleElementType(type);
if (isCompoundSubtype(singleElementType)) {
final clazz = (singleElementType as InterfaceType).classNode;
- compoundClassDependencies[node].add(clazz);
_checkPacking(node, packing, clazz, f);
}
final dimensions = sizeAnnotations.single;
@@ -462,20 +541,16 @@
node.addConstructor(ctor);
}
- /// Computes the field offsets (for all ABIs) in the compound and replaces
- /// the fields with getters and setters using these offsets.
- ///
- /// Returns the total size of the compound (for all ABIs).
- Map<Abi, int> _replaceFields(Class node, IndexedClass indexedClass) {
+ CompoundData _findFields(Class node) {
final types = <NativeTypeCfe>[];
final fields = <int, Field>{};
final getters = <int, Procedure>{};
final setters = <int, Procedure>{};
-
int i = 0;
for (final Member m in _compoundFieldMembers(node)) {
- final dartType = _compoundFieldMemberType(m);
+ final dartType = _compoundMemberType(m);
+ // Nullable.
NativeTypeCfe type;
if (isArrayType(dartType)) {
final sizeAnnotations = _getArraySizeAnnotations(m).toList();
@@ -508,7 +583,8 @@
}
if (m is Procedure && m.isSetter) {
final index = i - 1; // The corresponding getter's index.
- if (getters.containsKey(index)) {
+ final getter = getters[index];
+ if (getter != null && getter.name == m.name) {
setters[i - 1] = m;
}
}
@@ -518,8 +594,35 @@
final packing =
(!packingAnnotations.isEmpty) ? packingAnnotations.first : null;
- _annoteCompoundWithFields(node, types, packing);
- if (types.isEmpty) {
+ final compoundType = () {
+ if (types.whereType<InvalidNativeTypeCfe>().isNotEmpty) {
+ return InvalidNativeTypeCfe("Nested member invalid.");
+ }
+ if (node.superclass == structClass) {
+ return StructNativeTypeCfe(node, types, packing: packing);
+ }
+ return UnionNativeTypeCfe(node, types);
+ }();
+
+ List<CompoundField> fieldsFound = [];
+ for (int j = 0; j < i; j++) {
+ fieldsFound
+ .add(CompoundField(types[j], fields[j], getters[j], setters[j]));
+ }
+ return CompoundData(fieldsFound, packing, compoundType);
+ }
+
+ /// Computes the field offsets (for all ABIs) in the compound and replaces
+ /// the fields with getters and setters using these offsets.
+ ///
+ /// Returns the total size of the compound (for all ABIs).
+ void _replaceFields(
+ Class node, IndexedClass indexedClass, CompoundData compoundData) {
+ final compoundType = compoundData.compoundType as CompoundNativeTypeCfe;
+ final compoundLayout = compoundType.layout;
+
+ _annoteCompoundWithFields(node, compoundType.members, compoundData.packing);
+ if (compoundType.members.isEmpty) {
diagnosticReporter.report(
templateFfiEmptyStruct.withArguments(node.superclass.name, node.name),
node.fileOffset,
@@ -527,53 +630,46 @@
node.location.file);
}
- final compoundType = node.superclass == structClass
- ? StructNativeTypeCfe(node, types, packing: packing)
- : UnionNativeTypeCfe(node, types);
- compoundCache[node] = compoundType;
- final compoundLayout = compoundType.layout;
+ final unalignedAccess = compoundData.packing != null;
- final unalignedAccess = packing != null;
- for (final i in fields.keys) {
+ int i = 0;
+ for (final compoundField in compoundData.compoundFields) {
+ NativeTypeCfe type = compoundField.type;
+ Field field = compoundField.field;
+ Procedure getter = compoundField.getter;
+ Procedure setter = compoundField.setter;
+
final fieldOffsets = compoundLayout
.map((Abi abi, CompoundLayout v) => MapEntry(abi, v.offsets[i]));
- final methods = _generateMethodsForField(
- fields[i], types[i], fieldOffsets, unalignedAccess, indexedClass);
- methods.forEach((p) => node.addProcedure(p));
- }
- for (final Field f in fields.values) {
- node.fields.remove(f);
- }
+ if (field != null) {
+ _generateMethodsForField(
+ node, field, type, fieldOffsets, unalignedAccess, indexedClass);
+ }
- for (final i in getters.keys) {
- final fieldOffsets = compoundLayout
- .map((Abi abi, CompoundLayout v) => MapEntry(abi, v.offsets[i]));
- Procedure getter = getters[i];
- getter.function.body = types[i].generateGetterStatement(
- getter.function.returnType,
- getter.fileOffset,
- fieldOffsets,
- unalignedAccess,
- this);
- getter.isExternal = false;
- }
+ if (getter != null) {
+ getter.function.body = type.generateGetterStatement(
+ getter.function.returnType,
+ getter.fileOffset,
+ fieldOffsets,
+ unalignedAccess,
+ this);
+ getter.isExternal = false;
+ }
- for (final i in setters.keys) {
- final fieldOffsets = compoundLayout
- .map((Abi abi, CompoundLayout v) => MapEntry(abi, v.offsets[i]));
- Procedure setter = setters[i];
- setter.function.body = types[i].generateSetterStatement(
- setter.function.positionalParameters.single.type,
- setter.fileOffset,
- fieldOffsets,
- unalignedAccess,
- setter.function.positionalParameters.single,
- this);
- setter.isExternal = false;
- }
+ if (setter != null) {
+ setter.function.body = type.generateSetterStatement(
+ setter.function.positionalParameters.single.type,
+ setter.fileOffset,
+ fieldOffsets,
+ unalignedAccess,
+ setter.function.positionalParameters.single,
+ this);
+ setter.isExternal = false;
+ }
- return compoundLayout.map((k, v) => MapEntry(k, v.size));
+ i++;
+ }
}
// packing is `int?`.
@@ -596,7 +692,7 @@
InterfaceType(pragmaClass, Nullability.nonNullable, [])));
}
- List<Procedure> _generateMethodsForField(Field field, NativeTypeCfe type,
+ void _generateMethodsForField(Class node, Field field, NativeTypeCfe type,
Map<Abi, int> offsets, bool unalignedAccess, IndexedClass indexedClass) {
// TODO(johnniwinther): Avoid passing [indexedClass]. When compiling
// incrementally, [field] should already carry the references from
@@ -612,9 +708,10 @@
FunctionNode(getterStatement, returnType: field.type),
fileUri: field.fileUri, reference: getterReference)
..fileOffset = field.fileOffset
- ..isNonNullableByDefault = field.isNonNullableByDefault;
+ ..isNonNullableByDefault = field.isNonNullableByDefault
+ ..annotations = field.annotations;
+ node.addProcedure(getter);
- Procedure setter = null;
if (!field.isFinal) {
Reference setterReference =
indexedClass?.lookupSetterReference(field.name) ??
@@ -626,7 +723,7 @@
..fileOffset = field.fileOffset;
final setterStatement = type.generateSetterStatement(field.type,
field.fileOffset, offsets, unalignedAccess, argument, this);
- setter = Procedure(
+ final setter = Procedure(
field.name,
ProcedureKind.Setter,
FunctionNode(setterStatement,
@@ -635,15 +732,22 @@
reference: setterReference)
..fileOffset = field.fileOffset
..isNonNullableByDefault = field.isNonNullableByDefault;
+ node.addProcedure(setter);
}
- return [getter, if (setter != null) setter];
+ node.fields.remove(field);
}
/// Sample output:
- /// int #sizeOf => [24,24,16][_abi()];
- void _replaceSizeOfMethod(
- Class compound, Map<Abi, int> sizes, IndexedClass indexedClass) {
+ /// final int #sizeOf = [24,24,16][_abi()];
+ ///
+ /// If sizes are not supplied still emits a field so that the use site
+ /// transformer can still rewrite to it.
+ void _addSizeOfField(Class compound, IndexedClass indexedClass,
+ [Map<Abi, int> sizes = null]) {
+ if (sizes == null) {
+ sizes = Map.fromEntries(Abi.values.map((abi) => MapEntry(abi, 0)));
+ }
var name = Name("#sizeOf");
var getterReference = indexedClass?.lookupGetterReference(name);
final Field sizeOf = Field.immutable(name,
@@ -725,6 +829,32 @@
}
}
+class CompoundData {
+ final List<CompoundField> compoundFields;
+
+ // Nullable.
+ final int packing;
+
+ final NativeTypeCfe compoundType;
+
+ CompoundData(this.compoundFields, this.packing, this.compoundType);
+}
+
+class CompoundField {
+ final NativeTypeCfe type;
+
+ // Nullable.
+ final Field field;
+
+ // Nullable.
+ final Procedure getter;
+
+ // Nullable.
+ final Procedure setter;
+
+ CompoundField(this.type, this.field, this.getter, this.setter);
+}
+
/// The layout of a `Struct` or `Union` in one [Abi].
class CompoundLayout {
/// Size of the entire struct or union.
@@ -748,7 +878,7 @@
abstract class NativeTypeCfe {
factory NativeTypeCfe(FfiTransformer transformer, DartType dartType,
{List<int> arrayDimensions,
- Map<Class, CompoundNativeTypeCfe> compoundCache = const {}}) {
+ Map<Class, NativeTypeCfe> compoundCache = const {}}) {
if (transformer.isPrimitiveType(dartType)) {
final clazz = (dartType as InterfaceType).classNode;
final nativeType = transformer.getType(clazz);
@@ -772,6 +902,9 @@
final elementType = transformer.arraySingleElementType(dartType);
final elementCfeType =
NativeTypeCfe(transformer, elementType, compoundCache: compoundCache);
+ if (elementCfeType is InvalidNativeTypeCfe) {
+ return elementCfeType;
+ }
return ArrayNativeTypeCfe.multi(elementCfeType, arrayDimensions);
}
throw "Invalid type $dartType";
@@ -810,6 +943,40 @@
FfiTransformer transformer);
}
+class InvalidNativeTypeCfe implements NativeTypeCfe {
+ final String reason;
+
+ InvalidNativeTypeCfe(this.reason);
+
+ @override
+ Map<Abi, int> get alignment => throw reason;
+
+ @override
+ Constant generateConstant(FfiTransformer transformer) => throw reason;
+
+ @override
+ ReturnStatement generateGetterStatement(
+ DartType dartType,
+ int fileOffset,
+ Map<Abi, int> offsets,
+ bool unalignedAccess,
+ FfiTransformer transformer) =>
+ throw reason;
+
+ @override
+ ReturnStatement generateSetterStatement(
+ DartType dartType,
+ int fileOffset,
+ Map<Abi, int> offsets,
+ bool unalignedAccess,
+ VariableDeclaration argument,
+ FfiTransformer transformer) =>
+ throw reason;
+
+ @override
+ Map<Abi, int> get size => throw reason;
+}
+
class PrimitiveNativeTypeCfe implements NativeTypeCfe {
final NativeType nativeType;
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 860c2d2..8f9b4a3 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -388,7 +388,8 @@
final NativeType nt = getType(nativeClass);
if (nt == null) {
// User-defined compounds.
- Field sizeOfField = nativeClass.fields.single;
+ Field sizeOfField = nativeClass.fields
+ .firstWhere((field) => field.name == Name('#sizeOf'));
return StaticGet(sizeOfField);
}
final int size = nativeTypeSizes[nt.index];
@@ -505,8 +506,8 @@
PropertyGet(NullCheck(node.arguments.positional[0]),
arrayTypedDataBaseField.name, arrayTypedDataBaseField),
MethodInvocation(node.arguments.positional[1], numMultiplication.name,
- Arguments([StaticGet(clazz.fields.single)]), numMultiplication),
- StaticGet(clazz.fields.single),
+ Arguments([_inlineSizeOf(dartType)]), numMultiplication),
+ _inlineSizeOf(dartType),
dartType,
node.fileOffset);
diff --git a/tools/VERSION b/tools/VERSION
index f349f1c..6ae49c3 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 88
+PRERELEASE 89
PRERELEASE_PATCH 0
\ No newline at end of file