[vm,compiler] Fix serialization of ranges and arguments descriptors
Convert range boundaries with symbolic references to other instructions
into constant boundaries to avoid serializing extra references.
Specially handle serialization of arguments descriptors which are
cached in the VM isolate.
TEST=ci
Change-Id: Ifab3bb4d9b037aaefd81d38dd93d47cd4b42cf1d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/405571
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
index 7677a43..905603e 100644
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -98,6 +98,31 @@
AliasIdentity::AliasIdentity(FlowGraphDeserializer* d)
: value_(d->Read<intptr_t>()) {}
+void ArgumentsDescriptor::Write(FlowGraphSerializer* s) const {
+ if (IsCached()) {
+ // Simple argument descriptors are cached in the VM isolate.
+ // Write them as arguments count and query cache during deserialization.
+ ASSERT(TypeArgsLen() == 0);
+ ASSERT(NamedCount() == 0);
+ ASSERT(Count() == Size());
+ ASSERT(array_.InVMIsolateHeap());
+ s->Write<intptr_t>(Count());
+ } else {
+ ASSERT(array_.IsCanonical());
+ ASSERT(!array_.InVMIsolateHeap());
+ s->Write<intptr_t>(-1);
+ s->Write<const Array&>(array_);
+ }
+}
+
+ArrayPtr ArgumentsDescriptor::Read(FlowGraphDeserializer* d) {
+ const intptr_t num_args = d->Read<intptr_t>();
+ if (num_args < 0) {
+ return d->Read<const Array&>().ptr();
+ }
+ return NewBoxed(0, num_args);
+}
+
void BlockEntryInstr::WriteTo(FlowGraphSerializer* s) {
TemplateInstruction::WriteTo(s);
s->Write<intptr_t>(block_id_);
@@ -850,7 +875,7 @@
case UntaggedFunction::kInvokeFieldDispatcher: {
s->Write<const Class&>(Class::Handle(zone, x.Owner()));
s->Write<const String&>(String::Handle(zone, x.name()));
- s->Write<const Array&>(Array::Handle(zone, x.saved_args_desc()));
+ ArgumentsDescriptor(Array::Handle(zone, x.saved_args_desc())).Write(s);
return;
}
case UntaggedFunction::kDynamicInvocationForwarder: {
@@ -926,7 +951,8 @@
case UntaggedFunction::kInvokeFieldDispatcher: {
const Class& owner = d->Read<const Class&>();
const String& target_name = d->Read<const String&>();
- const Array& args_desc = d->Read<const Array&>();
+ const Array& args_desc =
+ Array::Handle(zone, ArgumentsDescriptor::Read(d));
return Function::ZoneHandle(
zone,
owner.GetInvocationDispatcher(
@@ -1650,7 +1676,8 @@
const auto& icdata = ICData::Cast(x);
Write<int8_t>(static_cast<int8_t>(icdata.rebind_rule()));
Write<const Function&>(Function::Handle(Z, icdata.Owner()));
- Write<const Array&>(Array::Handle(Z, icdata.arguments_descriptor()));
+ ArgumentsDescriptor(Array::Handle(Z, icdata.arguments_descriptor()))
+ .Write(this);
Write<intptr_t>(icdata.deopt_id());
Write<intptr_t>(icdata.NumArgsTested());
if (icdata.rebind_rule() == ICData::kStatic) {
@@ -1940,7 +1967,8 @@
const ICData::RebindRule rebind_rule =
static_cast<ICData::RebindRule>(Read<int8_t>());
const auto& owner = Read<const Function&>();
- const auto& arguments_descriptor = Read<const Array&>();
+ const auto& arguments_descriptor =
+ Array::Handle(Z, ArgumentsDescriptor::Read(this));
const intptr_t deopt_id = Read<intptr_t>();
const intptr_t num_args_tested = Read<intptr_t>();
@@ -2262,14 +2290,17 @@
}
void Range::Write(FlowGraphSerializer* s) const {
- min_.Write(s);
- max_.Write(s);
+ // Drop symbolic range boundaries - they are not useful
+ // when flow graph is serialized/deserialized.
+ min_.LowerBound().Write(s);
+ max_.UpperBound().Write(s);
}
Range::Range(FlowGraphDeserializer* d)
: min_(RangeBoundary(d)), max_(RangeBoundary(d)) {}
void RangeBoundary::Write(FlowGraphSerializer* s) const {
+ ASSERT(!IsSymbol());
s->Write<int8_t>(kind_);
s->Write<int64_t>(value_);
s->Write<int64_t>(offset_);
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index d0ab521..ba21431 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -442,6 +442,12 @@
return buf.buffer();
}
+bool ArgumentsDescriptor::IsCached() const {
+ const intptr_t num_arguments = Count();
+ return (num_arguments < kCachedDescriptorCount) &&
+ (array_.ptr() == cached_args_descriptors_[num_arguments]);
+}
+
ArrayPtr ArgumentsDescriptor::New(intptr_t type_args_len,
intptr_t num_arguments,
intptr_t size_arguments,
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index e79688b..1c51bda 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -15,6 +15,8 @@
// Forward declarations.
class Array;
class Closure;
+class FlowGraphDeserializer;
+class FlowGraphSerializer;
class Function;
class Instance;
class Integer;
@@ -132,6 +134,9 @@
return Array::ContainsCompressedPointers();
}
+ void Write(FlowGraphSerializer* s) const;
+ static ArrayPtr Read(FlowGraphDeserializer* d);
+
private:
// Absolute indices into the array.
// Keep these in sync with the constants in invocation_mirror_patch.dart.
@@ -174,6 +179,8 @@
return kFirstNamedEntryIndex + (index * kNamedEntrySize) + kPositionOffset;
}
+ bool IsCached() const;
+
const Array& array_;
// A cache of VM heap allocated arguments descriptors.