-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
In https://github.com/osa1/protobuf.dart/tree/inlining_issue I add a bunch of inline pragmas to two higher-order functions and a few small functions.
Inlining these higher-order functions should eliminate indirect calls when calling the function arguments as in each call site the closure being passed is a function expression.
However currently AOT does not seem to fold field loads from closures and contexts.
If I manually inline _readPacked (by copy-pasting it into each of the call sites), that improves runtime of from_binary benchmark 7%. The diff for this change is at the end.
To repro:
- Clone the repo and switch to the
inlining_issuebranch. - In benchmarks directory:
./tool/compile_protos.sh(requires protoc with Dart plugin)dart pub getdart compile exe bin/from_binary.dart
I'm not fluent in VM's flow graph IR, but with --extra-gen-snapshot-options=--print-flow-graph-filter=_mergeFromCodedBufferReader,--print-flow-graph-optimized,--compiler-passes=\*Inlining and inline pragmas, I see code like
v525 <- Constant(#Function '<anonymous closure>': static.) T{Function}
...
v519 <- AllocateContext:10(num_variables=2) T{Context}
StoreField(v519 . input = v84 T{CodedBufferReader})
StoreField(v519 . readFunc = v82 T{_Closure})
...
v524 <- AllocateClosure:14(v525 T{Function}, v519) T{_Closure}
...
v4632 <- LoadField(v524 T{_Closure} . Closure.context {final}) T{!null}
...
v4636 <- LoadField(v4632 . readFunc {final}) T{(dynamic) => void}
v4637 <- ClosureCall:18( closure=v4636<0>, v4636)
(this is in an "after inlining" block)
Here LoadField(v524, ...) could be folded, which would then allow folding LoadField(v4632, ...), which I suspect in the end would give us the optimizations.
Inlining _readPacked manually is not ideal as that would potentially increase binary sizes on the browsers without improving runtime perf. Ideally I want to do this with backend-specific pragmas.
Diff for manually inlining `_readPacked`
diff --git a/protobuf/lib/src/protobuf/coded_buffer.dart b/protobuf/lib/src/protobuf/coded_buffer.dart
index a102cbb..ca5d26d 100644
--- a/protobuf/lib/src/protobuf/coded_buffer.dart
+++ b/protobuf/lib/src/protobuf/coded_buffer.dart
@@ -130,7 +130,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_BOOL:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readBool()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readBool());
+ }
+ });
} else {
list.add(input.readBool());
}
@@ -146,7 +150,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_FLOAT:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readFloat()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readFloat());
+ }
+ });
} else {
list.add(input.readFloat());
}
@@ -154,7 +162,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_DOUBLE:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readDouble()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readDouble());
+ }
+ });
} else {
list.add(input.readDouble());
}
@@ -173,7 +185,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_INT32:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readInt32()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readInt32());
+ }
+ });
} else {
list.add(input.readInt32());
}
@@ -181,7 +197,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_INT64:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readInt64()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readInt64());
+ }
+ });
} else {
list.add(input.readInt64());
}
@@ -189,7 +209,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_SINT32:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readSint32()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readSint32());
+ }
+ });
} else {
list.add(input.readSint32());
}
@@ -197,7 +221,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_SINT64:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readSint64()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readSint64());
+ }
+ });
} else {
list.add(input.readSint64());
}
@@ -205,7 +233,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_UINT32:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readUint32()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readUint32());
+ }
+ });
} else {
list.add(input.readUint32());
}
@@ -213,7 +245,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_UINT64:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readUint64()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readUint64());
+ }
+ });
} else {
list.add(input.readUint64());
}
@@ -221,7 +257,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_FIXED32:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readFixed32()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readFixed32());
+ }
+ });
} else {
list.add(input.readFixed32());
}
@@ -229,7 +269,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_FIXED64:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readFixed64()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readFixed64());
+ }
+ });
} else {
list.add(input.readFixed64());
}
@@ -237,7 +281,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_SFIXED32:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readSfixed32()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readSfixed32());
+ }
+ });
} else {
list.add(input.readSfixed32());
}
@@ -245,7 +293,11 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
case PbFieldType._REPEATED_SFIXED64:
final list = fs._ensureRepeatedField(meta, fi);
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
- _readPacked(input, () => list.add(input.readSfixed64()));
+ input._withLimit(input.readInt32(), () {
+ while (!input.isAtEnd()) {
+ list.add(input.readSfixed64());
+ }
+ });
} else {
list.add(input.readSfixed64());
}
@@ -269,14 +321,6 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
}
}
-void _readPacked(CodedBufferReader input, void Function() readFunc) {
- input._withLimit(input.readInt32(), () {
- while (!input.isAtEnd()) {
- readFunc();
- }
- });
-}
-
void _readPackableToListEnum(
List list,
BuilderInfo meta,cc @mraleph