[vm] Check compiler flags for Dart_Save/LoadTypeFeedback.

Change-Id: Ic733591ce1cac7d69fde28a115f11d43902923bc
Reviewed-on: https://dart-review.googlesource.com/c/90640
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index 2a9f62d..442db7c 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -316,12 +316,33 @@
       call_sites_(Array::Handle()),
       call_site_(ICData::Handle()) {}
 
+// These flags affect deopt ids.
+static char* CompilerFlags() {
+  TextBuffer buffer(64);
+
+#define ADD_FLAG(flag) buffer.AddString(FLAG_##flag ? " " #flag : "no " #flag)
+  ADD_FLAG(enable_asserts);
+  ADD_FLAG(use_field_guards);
+  ADD_FLAG(use_osr);
+  ADD_FLAG(causal_async_stacks);
+  ADD_FLAG(fields_may_be_reset);
+#undef ADD_FLAG
+  return buffer.Steal();
+}
+
 void TypeFeedbackSaver::WriteHeader() {
   const char* expected_version = Version::SnapshotString();
   ASSERT(expected_version != NULL);
   const intptr_t version_len = strlen(expected_version);
   stream_->WriteBytes(reinterpret_cast<const uint8_t*>(expected_version),
                       version_len);
+
+  char* expected_features = CompilerFlags();
+  ASSERT(expected_features != NULL);
+  const intptr_t features_len = strlen(expected_features);
+  stream_->WriteBytes(reinterpret_cast<const uint8_t*>(expected_features),
+                      features_len + 1);
+  free(expected_features);
 }
 
 void TypeFeedbackSaver::SaveClasses() {
@@ -534,6 +555,27 @@
   }
   stream_->Advance(version_len);
 
+  char* expected_features = CompilerFlags();
+  ASSERT(expected_features != NULL);
+  const intptr_t expected_len = strlen(expected_features);
+
+  const char* features =
+      reinterpret_cast<const char*>(stream_->AddressOfCurrentPosition());
+  ASSERT(features != NULL);
+  intptr_t buffer_len = Utils::StrNLen(features, stream_->PendingBytes());
+  if ((buffer_len != expected_len) ||
+      strncmp(features, expected_features, expected_len)) {
+    const String& msg = String::Handle(String::NewFormatted(
+        Heap::kOld,
+        "Feedback not compatible with the current VM configuration: "
+        "the feedback requires '%.*s' but the VM has '%s'",
+        static_cast<int>(buffer_len > 1024 ? 1024 : buffer_len), features,
+        expected_features));
+    free(expected_features);
+    return ApiError::New(msg, Heap::kOld);
+  }
+  free(expected_features);
+  stream_->Advance(expected_len + 1);
   return Error::null();
 }
 
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 9e7af23..e72d3e9 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -750,6 +750,8 @@
                        FLAG_use_field_guards);
       ADD_ISOLATE_FLAG(use_osr, use_osr, FLAG_use_osr);
     }
+    buffer.AddString(FLAG_causal_async_stacks ? " causal_async_stacks"
+                                              : " no-causal_async_stacks");
 
 // Generated code must match the host architecture and ABI.
 #if defined(TARGET_ARCH_ARM)