Reapply "[vm] Add tests for determinism of script and AppJIT snapshots."

 - Fix assembler->Stop("My address is not deterministic").
 - Skip tests on -cdartk + simulators as DFE is too slow.

Bug: https://github.com/dart-lang/sdk/issues/31427
Bug: https://github.com/dart-lang/sdk/issues/33264
Change-Id: Id79a8b8c8fc4b3842fcd1d3827d6d4551890b794
Reviewed-on: https://dart-review.googlesource.com/57483
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
index 5bed503..c5db6b9 100644
--- a/runtime/bin/snapshot_utils.cc
+++ b/runtime/bin/snapshot_utils.cc
@@ -13,6 +13,8 @@
 #include "include/dart_api.h"
 #include "platform/utils.h"
 
+#define LOG_SECTION_BOUNDARIES false
+
 namespace dart {
 namespace bin {
 
@@ -288,12 +290,18 @@
   ASSERT(file->Position() == kAppSnapshotHeaderSize);
 
   file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+  if (LOG_SECTION_BOUNDARIES) {
+    Log::PrintErr("%" Px64 ": VM Data\n", file->Position());
+  }
   if (!file->WriteFully(vm_data_buffer, vm_data_size)) {
     ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
   }
 
   if (vm_instructions_size != 0) {
     file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+    if (LOG_SECTION_BOUNDARIES) {
+      Log::PrintErr("%" Px64 ": VM Instructions\n", file->Position());
+    }
     if (!file->WriteFully(vm_instructions_buffer, vm_instructions_size)) {
       ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
                 filename);
@@ -301,12 +309,18 @@
   }
 
   file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+  if (LOG_SECTION_BOUNDARIES) {
+    Log::PrintErr("%" Px64 ": Isolate Data\n", file->Position());
+  }
   if (!file->WriteFully(isolate_data_buffer, isolate_data_size)) {
     ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n", filename);
   }
 
   if (isolate_instructions_size != 0) {
     file->SetPosition(Utils::RoundUp(file->Position(), kAppSnapshotPageSize));
+    if (LOG_SECTION_BOUNDARIES) {
+      Log::PrintErr("%" Px64 ": Isolate Instructions\n", file->Position());
+    }
     if (!file->WriteFully(isolate_instructions_buffer,
                           isolate_instructions_size)) {
       ErrorExit(kErrorExitCode, "Unable to write snapshot file '%s'\n",
diff --git a/runtime/tests/vm/dart/appjit_cha_deopt_test.dart b/runtime/tests/vm/dart/appjit_cha_deopt_test.dart
new file mode 100644
index 0000000..9c6f60f
--- /dev/null
+++ b/runtime/tests/vm/dart/appjit_cha_deopt_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2018, 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.
+
+// VMOptions=--optimization-counter-threshold=100
+
+// Verify that app-jit snapshot contains dependencies between classes and CHA
+// optimized code.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as p;
+
+import 'snapshot_test_helper.dart';
+
+const snapshotName = 'app.jit';
+
+Future<void> main() async {
+  final Directory temp = Directory.systemTemp.createTempSync();
+  final snapshotPath = p.join(temp.path, 'app.jit');
+  final testPath = Platform.script
+      .toFilePath()
+      .replaceAll(new RegExp(r'_test.dart$'), '_test_body.dart');
+
+  await temp.create();
+  try {
+    final trainingResult = await runDartBinary('TRAINING RUN', [
+      '--snapshot=$snapshotPath',
+      '--snapshot-kind=app-jit',
+      testPath,
+      '--train'
+    ]);
+    expectOutput("OK(Trained)", trainingResult);
+    final runResult = await runDartBinary('RUN FROM SNAPSHOT', [snapshotPath]);
+    expectOutput("OK(Run)", runResult);
+  } finally {
+    await temp.delete(recursive: true);
+  }
+}
diff --git a/runtime/tests/vm/dart/appjit_test_body.dart b/runtime/tests/vm/dart/appjit_cha_deopt_test_body.dart
similarity index 100%
rename from runtime/tests/vm/dart/appjit_test_body.dart
rename to runtime/tests/vm/dart/appjit_cha_deopt_test_body.dart
diff --git a/runtime/tests/vm/dart/appjit_determinism_test.dart b/runtime/tests/vm/dart/appjit_determinism_test.dart
new file mode 100644
index 0000000..f5116a8
--- /dev/null
+++ b/runtime/tests/vm/dart/appjit_determinism_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2018, 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.
+
+// Verify creating an app-jit snapshot twice generates the same bits.
+
+import 'dart:async';
+import 'snapshot_test_helper.dart';
+
+int fib(int n) {
+  if (n <= 1) return 1;
+  return fib(n - 1) + fib(n - 2);
+}
+
+Future<void> main(List<String> args) async {
+  if (args.contains('--child')) {
+    print(fib(35));
+    return;
+  }
+
+  await checkDeterministicSnapshot("app-jit", "14930352");
+}
diff --git a/runtime/tests/vm/dart/appjit_test.dart b/runtime/tests/vm/dart/appjit_test.dart
deleted file mode 100644
index 6fbe998..0000000
--- a/runtime/tests/vm/dart/appjit_test.dart
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2018, 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.
-
-// VMOptions=--optimization-counter-threshold=100
-
-// Verify that app-jit snapshot contains dependencies between classes and CHA
-// optimized code.
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:expect/expect.dart';
-import 'package:path/path.dart' as p;
-
-class Result {
-  final String cmdline;
-  final ProcessResult processResult;
-
-  Result(this.cmdline, this.processResult);
-}
-
-void reportError(Result result, String msg) {
-  print('running ${result.cmdline}:');
-  if (result.processResult.stdout.isNotEmpty) {
-    print('''
-
-Command stdout:
-${result.processResult.stdout}''');
-  }
-
-  if (result.processResult.stderr.isNotEmpty) {
-    print('''
-
-Command stderr:
-${result.processResult.stderr}''');
-  }
-
-  Expect.fail(msg);
-}
-
-void expectOutput(String what, Result result) {
-  if (result.processResult.stdout.trim() != what) {
-    reportError(result, 'Expected test to print \'${what}\' to stdout');
-  }
-}
-
-Future<Result> runDartBinary(String prefix, List<String> arguments) async {
-  final binary = Platform.executable;
-  final actualArguments = <String>[]
-    ..addAll(Platform.executableArguments)
-    ..addAll(arguments);
-  final processResult = await Process.run(binary, actualArguments);
-  final result = new Result(
-      '[$prefix] ${binary} ${actualArguments.join(' ')}', processResult);
-  if (result.processResult.exitCode != 0) {
-    reportError(result,
-        '[$prefix] Process finished with non-zero exit code ${result.processResult.exitCode}');
-  }
-  return result;
-}
-
-const snapshotName = 'app.jit';
-
-void main() async {
-  final Directory temp = Directory.systemTemp.createTempSync();
-  final snapshotPath = p.join(temp.path, 'app.jit');
-  final testPath = Platform.script
-      .toFilePath()
-      .replaceAll(new RegExp(r'_test.dart$'), '_test_body.dart');
-
-  await temp.create();
-  try {
-    final trainingResult = await runDartBinary('TRAINING RUN', [
-      '--snapshot=$snapshotPath',
-      '--snapshot-kind=app-jit',
-      testPath,
-      '--train'
-    ]);
-    expectOutput("OK(Trained)", trainingResult);
-    final runResult = await runDartBinary('RUN FROM SNAPSHOT', [snapshotPath]);
-    expectOutput("OK(Run)", runResult);
-  } finally {
-    await temp.delete(recursive: true);
-  }
-}
diff --git a/runtime/tests/vm/dart/script_determinism_test.dart b/runtime/tests/vm/dart/script_determinism_test.dart
new file mode 100644
index 0000000..4b51b4f
--- /dev/null
+++ b/runtime/tests/vm/dart/script_determinism_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2018, 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.
+
+// Verify creating a script snapshot twice generates the same bits.
+
+import 'dart:async';
+import 'snapshot_test_helper.dart';
+
+int fib(int n) {
+  if (n <= 1) return 1;
+  return fib(n - 1) + fib(n - 2);
+}
+
+Future<void> main(List<String> args) async {
+  if (args.contains('--child')) {
+    print(fib(35));
+    return;
+  }
+
+  await checkDeterministicSnapshot("script", "");
+}
diff --git a/runtime/tests/vm/dart/snapshot_test_helper.dart b/runtime/tests/vm/dart/snapshot_test_helper.dart
new file mode 100644
index 0000000..2de2bbf
--- /dev/null
+++ b/runtime/tests/vm/dart/snapshot_test_helper.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2018, 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.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as p;
+
+class Result {
+  final String cmdline;
+  final ProcessResult processResult;
+
+  Result(this.cmdline, this.processResult);
+}
+
+void reportError(Result result, String msg) {
+  print('running ${result.cmdline}:');
+  if (result.processResult.stdout.isNotEmpty) {
+    print('''
+
+Command stdout:
+${result.processResult.stdout}''');
+  }
+
+  if (result.processResult.stderr.isNotEmpty) {
+    print('''
+
+Command stderr:
+${result.processResult.stderr}''');
+  }
+
+  Expect.fail(msg);
+}
+
+void expectOutput(String what, Result result) {
+  if (result.processResult.stdout.trim() != what) {
+    reportError(result, 'Expected test to print \'${what}\' to stdout');
+  }
+}
+
+Future<Result> runDartBinary(String prefix, List<String> arguments) async {
+  final binary = Platform.executable;
+  final actualArguments = <String>[]
+    ..addAll(Platform.executableArguments)
+    ..addAll(arguments);
+  print("+ $binary " + actualArguments.join(" "));
+  final processResult = await Process.run(binary, actualArguments);
+  final result = new Result(
+      '[$prefix] ${binary} ${actualArguments.join(' ')}', processResult);
+  if (result.processResult.exitCode != 0) {
+    reportError(result,
+        '[$prefix] Process finished with non-zero exit code ${result.processResult.exitCode}');
+  }
+  return result;
+}
+
+Future<Null> checkDeterministicSnapshot(
+    String snapshotKind, String expectedStdout) async {
+  final Directory temp = Directory.systemTemp.createTempSync();
+  final snapshot1Path = p.join(temp.path, 'snapshot1');
+  final snapshot2Path = p.join(temp.path, 'snapshot2');
+
+  try {
+    final generate1Result = await runDartBinary('GENERATE SNAPSHOT 1', [
+      '--deterministic',
+      '--snapshot=$snapshot1Path',
+      '--snapshot-kind=$snapshotKind',
+      Platform.script.toFilePath(),
+      '--child',
+    ]);
+    expectOutput(expectedStdout, generate1Result);
+
+    final generate2Result = await runDartBinary('GENERATE SNAPSHOT 2', [
+      '--deterministic',
+      '--snapshot=$snapshot2Path',
+      '--snapshot-kind=$snapshotKind',
+      Platform.script.toFilePath(),
+      '--child',
+    ]);
+    expectOutput(expectedStdout, generate2Result);
+
+    var snapshot1Bytes = await new File(snapshot1Path).readAsBytes();
+    var snapshot2Bytes = await new File(snapshot2Path).readAsBytes();
+
+    Expect.equals(snapshot1Bytes.length, snapshot2Bytes.length);
+    for (var i = 0; i < snapshot1Bytes.length; i++) {
+      if (snapshot1Bytes[i] != snapshot2Bytes[i]) {
+        Expect.fail("Snapshots are not bitwise equal!");
+      }
+    }
+  } finally {
+    await temp.delete(recursive: true);
+  }
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 92c4f22..00161d8 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -23,6 +23,9 @@
 [ $builder_tag == asan ]
 cc/CodeImmutability: Fail, OK # Address Sanitizer turns a crash into a failure.
 
+[ $builder_tag == optimization_counter_threshold ]
+dart/appjit_cha_deopt_test: SkipByDesign # Test needs to a particular opt-counter value
+
 [ $compiler == app_jit ]
 dart/snapshot_version_test: Fail, OK # Expects to find script snapshot relative to Dart source.
 
@@ -54,6 +57,7 @@
 [ $compiler == dartk ]
 cc/DartAPI_New: Fail # Issue #33041
 cc/DartAPI_TypeGetParameterizedTypes: Crash # Issue 33042
+dart/appjit_cha_deopt_test: SkipSlow # Issue 33266
 dart/redirection_type_shuffling_test/00: RuntimeError
 dart/redirection_type_shuffling_test/none: RuntimeError
 
@@ -214,6 +218,11 @@
 cc/ScriptSnapshot1: Fail, Crash, OK # Script snapshots not supported in Dart 2
 cc/ScriptSnapshotsUpdateSubclasses: Fail, Crash, OK # Script snapshots not supported in Dart 2
 
+[ $compiler == dartk && ($arch == simarm || $arch == simarm64 || $arch == simdbc || $arch == simdbc64) ]
+dart/appjit_cha_deopt_test: SkipSlow # DFE too slow
+dart/appjit_determinism_test: SkipSlow # DFE too slow
+dart/script_determinism_test: SkipSlow # DFE too slow
+
 # Enabling of dartk for sim{arm,arm64,dbc64} revelaed these test failures, which
 # are to be triaged.  Isolate tests are skipped on purpose due to the usage of
 # batch mode.
@@ -221,6 +230,11 @@
 dart/data_uri_spawn_test: Skip # Please triage.
 dart/snapshot_version_test: RuntimeError # Please triage.
 
+[ $compiler != dartk && $compiler != none ]
+dart/appjit_cha_deopt_test: SkipByDesign # Test needs to run from source
+dart/appjit_determinism_test: SkipByDesign # Test needs to run from source
+dart/script_determinism_test: SkipByDesign # Test needs to run from source
+
 [ $compiler == dartkp && !$strong ]
 dart/truncating_ints_test: Skip # This test cannot be run in dartkp/legacy mode (gen_kernel does not pass --limit-ints-to-64-bits in legacy mode).
 
@@ -287,9 +301,6 @@
 cc/RegExp_TwoByteString: Skip # TODO(vegorov) These tests don't seem to work if FLAG_interpret_irregexp is switched on by default because they attempt to call regexp functions directly instead of going through JSSyntaxRegExp_ExecuteMatch.
 cc/RegenerateAllocStubs: Skip # This test is meaningless for DBC as allocation stubs are not used.
 
-[ $arch == simdbc64 || $builder_tag == optimization_counter_threshold || $compiler != none ]
-dart/appjit_test: Skip
-
 [ $compiler == dart2analyzer || $compiler == dart2js ]
 dart/data_uri*test: Skip # Data uri's not supported by dart2js or the analyzer.
 
@@ -336,5 +347,7 @@
 dart/redirection_type_shuffling_test: SkipByDesign # Imports dart:mirrors
 
 [ $hot_reload || $hot_reload_rollback ]
+dart/appjit_determinism_test: Skip # Reload affects determinisim
+dart/script_determinism_test: Skip # We can shutdown an isolate before it reloads.
 dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
 dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 2208c17..989960e 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -19,6 +19,8 @@
 #include "vm/timeline.h"
 #include "vm/version.h"
 
+#define LOG_SECTION_BOUNDARIES false
+
 namespace dart {
 
 static RawObject* AllocateUninitialized(PageSpace* old_space, intptr_t size) {
@@ -49,6 +51,10 @@
 }
 
 void SerializationCluster::WriteAndMeasureAlloc(Serializer* serializer) {
+  if (LOG_SECTION_BOUNDARIES) {
+    OS::PrintErr("Data + %" Px ": Alloc %s\n", serializer->bytes_written(),
+                 name_);
+  }
   intptr_t start_size = serializer->bytes_written() + serializer->GetDataSize();
   intptr_t start_objects = serializer->next_ref_index();
   WriteAlloc(serializer);
@@ -59,6 +65,10 @@
 }
 
 void SerializationCluster::WriteAndMeasureFill(Serializer* serializer) {
+  if (LOG_SECTION_BOUNDARIES) {
+    OS::PrintErr("Data + %" Px ": Fill %s\n", serializer->bytes_written(),
+                 name_);
+  }
   intptr_t start = serializer->bytes_written();
   WriteFill(serializer);
   intptr_t stop = serializer->bytes_written();
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index 86e7876..c418f4f 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -3240,13 +3240,6 @@
     BranchLink(&StubCode::PrintStopMessage_entry()->label());
     PopList((1 << R0) | (1 << IP) | (1 << LR));  // Restore R0, IP, LR.
   }
-  // Emit the message address before the svc instruction, so that we can
-  // 'unstop' and continue execution in the simulator or jump to the next
-  // instruction in gdb.
-  Label stop;
-  b(&stop);
-  Emit(reinterpret_cast<int32_t>(message));
-  Bind(&stop);
   bkpt(Instr::kStopMessageCode);
 }
 
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index a322f7c..305b3a9 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -221,11 +221,6 @@
   if (FLAG_print_stop_message) {
     UNIMPLEMENTED();
   }
-  Label stop;
-  b(&stop);
-  Emit(Utils::Low32Bits(reinterpret_cast<int64_t>(message)));
-  Emit(Utils::High32Bits(reinterpret_cast<int64_t>(message)));
-  Bind(&stop);
   brk(Instr::kStopMessageCode);
 }
 
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 0ba938b..ae69a35 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2320,9 +2320,6 @@
     movl(EAX, Immediate(reinterpret_cast<int32_t>(message)));
     Call(*StubCode::PrintStopMessage_entry());  // Passing message in EAX.
     popl(EAX);                                  // Restore EAX.
-  } else {
-    // Emit the message address as immediate operand in the test instruction.
-    testl(EAX, Immediate(reinterpret_cast<int32_t>(message)));
   }
   // Emit the int3 instruction.
   int3();  // Execution can be resumed with the 'cont' command in gdb.
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index e08f526..7bcd4a0 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1307,8 +1307,8 @@
 }
 
 void Assembler::Stop(const char* message, bool fixed_length_encoding) {
-  int64_t message_address = reinterpret_cast<int64_t>(message);
   if (FLAG_print_stop_message) {
+    int64_t message_address = reinterpret_cast<int64_t>(message);
     pushq(TMP);  // Preserve TMP register.
     pushq(RDI);  // Preserve RDI register.
     if (fixed_length_encoding) {
@@ -1322,14 +1322,6 @@
     call(&StubCode::PrintStopMessage_entry()->label());
     popq(RDI);  // Restore RDI register.
     popq(TMP);  // Restore TMP register.
-  } else {
-    // Emit the lower half and the higher half of the message address as
-    // immediate operands in the test rax instructions.
-    testl(RAX, Immediate(Utils::Low32Bits(message_address)));
-    uint32_t hi = Utils::High32Bits(message_address);
-    if (hi != 0) {
-      testl(RAX, Immediate(hi));
-    }
   }
   // Emit the int3 instruction.
   int3();  // Execution can be resumed with the 'cont' command in gdb.
diff --git a/runtime/vm/compiler/assembler/disassembler_arm.cc b/runtime/vm/compiler/assembler/disassembler_arm.cc
index 5c718de..491a2b4 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm.cc
@@ -656,8 +656,11 @@
           if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) {
             Format(instr, "bkpt #'imm12_4");
             if (instr->BkptField() == Instr::kStopMessageCode) {
-              const char* message = *reinterpret_cast<const char**>(
-                  reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
+              const char* message = "Stop messages not enabled";
+              if (FLAG_print_stop_message) {
+                message = *reinterpret_cast<const char**>(
+                    reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
+              }
               buffer_pos_ += Utils::SNPrint(current_position_in_buffer(),
                                             remaining_size_in_buffer(),
                                             " ; \"%s\"", message);
diff --git a/runtime/vm/compiler/assembler/disassembler_arm64.cc b/runtime/vm/compiler/assembler/disassembler_arm64.cc
index f5b49f7..14fb8a6 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm64.cc
@@ -886,8 +886,11 @@
              (instr->Bits(21, 3) == 1)) {
     Format(instr, "brk 'imm16");
     if (instr->Imm16Field() == Instr::kStopMessageCode) {
-      const char* message = *reinterpret_cast<const char**>(
-          reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize);
+      const char* message = "Stop messages not enabled";
+      if (FLAG_print_stop_message) {
+        message = *reinterpret_cast<const char**>(
+            reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize);
+      }
       buffer_pos_ +=
           Utils::SNPrint(current_position_in_buffer(),
                          remaining_size_in_buffer(), " ; \"%s\"", message);
diff --git a/runtime/vm/compiler/assembler/disassembler_x86.cc b/runtime/vm/compiler/assembler/disassembler_x86.cc
index 56b3878..a25530c 100644
--- a/runtime/vm/compiler/assembler/disassembler_x86.cc
+++ b/runtime/vm/compiler/assembler/disassembler_x86.cc
@@ -1234,8 +1234,11 @@
 #if defined(TARGET_ARCH_IA32)
   // Recognize stop pattern.
   if (*data == 0xCC) {
-    const char* text = *reinterpret_cast<const char**>(data - 4);
-    Print("  STOP:'%s'", text);
+    const char* message = "Stop messages not enabled";
+    if (FLAG_print_stop_message) {
+      message = *reinterpret_cast<const char**>(data - 4);
+    }
+    Print("  STOP:'%s'", message);
   }
 #endif
 }
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index db1f4a2..ae20a77 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -84,13 +84,15 @@
 
 static void DeterministicModeHandler(bool value) {
   if (value) {
-    FLAG_background_compilation = false;
-    FLAG_collect_code = false;
+    FLAG_background_compilation = false;  // Timing dependent.
+    FLAG_collect_code = false;            // Timing dependent.
     FLAG_random_seed = 0x44617274;  // "Dart"
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
     FLAG_load_deferred_eagerly = true;
+    FLAG_print_stop_message = false;  // Embedds addresses in instructions.
 #else
     COMPILE_ASSERT(FLAG_load_deferred_eagerly);
+    COMPILE_ASSERT(!FLAG_print_stop_message);
 #endif
   }
 }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index d6a2533..bd98c07 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7070,6 +7070,7 @@
   result.set_parameter_types(Object::empty_array());
   result.set_parameter_names(Object::empty_array());
   result.set_name(name);
+  result.set_kind_tag(0);  // Ensure determinism of uninitialized bits.
   result.set_kind(kind);
   result.set_recognized_kind(MethodRecognizer::kUnknown);
   result.set_modifier(RawFunction::kNoModifier);
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 1efbaa8..9bb3ca9 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1559,8 +1559,11 @@
             SimulatorDebugger dbg(this);
             int32_t imm = instr->BkptField();
             if (imm == Instr::kStopMessageCode) {
-              const char* message = *reinterpret_cast<const char**>(
-                  reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
+              const char* message = "Stop messages not enabled";
+              if (FLAG_print_stop_message) {
+                message = *reinterpret_cast<const char**>(
+                    reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
+              }
               set_pc(get_pc() + Instr::kInstrSize);
               dbg.Stop(instr, message);
             } else {
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 5493d43..e482786 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -1651,8 +1651,11 @@
     SimulatorDebugger dbg(this);
     int32_t imm = instr->Imm16Field();
     if (imm == Instr::kStopMessageCode) {
-      const char* message = *reinterpret_cast<const char**>(
-          reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize);
+      const char* message = "Stop messages not enabled";
+      if (FLAG_print_stop_message) {
+        message = *reinterpret_cast<const char**>(
+            reinterpret_cast<intptr_t>(instr) - 2 * Instr::kInstrSize);
+      }
       set_pc(get_pc() + Instr::kInstrSize);
       dbg.Stop(instr, message);
     } else {