[vm/bytecode] Remove unreachable bytecode

Change-Id: I29393604547038cf359b8e19ea48078dd0eea3b1
Reviewed-on: https://dart-review.googlesource.com/c/81201
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Auto-Submit: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/assembler.dart b/pkg/vm/lib/bytecode/assembler.dart
index dce3410..b45b4c1 100644
--- a/pkg/vm/lib/bytecode/assembler.dart
+++ b/pkg/vm/lib/bytecode/assembler.dart
@@ -10,15 +10,19 @@
 import 'exceptions.dart' show ExceptionsTable;
 
 class Label {
+  final bool allowsBackwardJumps;
   List<int> _jumps = <int>[];
   int offset = -1;
 
-  Label();
+  Label({this.allowsBackwardJumps: false});
 
   bool get isBound => offset >= 0;
 
   int jumpOperand(int jumpOffset) {
     if (isBound) {
+      if (offset <= jumpOffset && !allowsBackwardJumps) {
+        throw 'Backward jump to this label is not allowed';
+      }
       // Jump instruction takes an offset in DBC words.
       return (offset - jumpOffset) >> BytecodeAssembler.kLog2BytesPerBytecode;
     }
@@ -44,6 +48,7 @@
   final Uint32List _encodeBufferIn;
   final Uint8List _encodeBufferOut;
   final ExceptionsTable exceptionsTable = new ExceptionsTable();
+  bool isUnreachable = false;
 
   BytecodeAssembler._(this._encodeBufferIn, this._encodeBufferOut);
 
@@ -60,9 +65,15 @@
     for (int jumpOffset in jumps) {
       patchJump(jumpOffset, label.jumpOperand(jumpOffset));
     }
+    if (jumps.isNotEmpty || label.allowsBackwardJumps) {
+      isUnreachable = false;
+    }
   }
 
   void emitWord(int word) {
+    if (isUnreachable) {
+      return;
+    }
     _encodeBufferIn[0] = word; // TODO(alexmarkov): Which endianness to use?
     bytecode.addAll(_encodeBufferOut);
   }
@@ -145,8 +156,17 @@
     emitWord(_encode0(opcode));
   }
 
+  void _emitJumpBytecode(Opcode opcode, Label label) {
+    assert(isJump(opcode));
+    if (!isUnreachable) {
+      // Do not use label if not generating instruction.
+      emitWord(_encodeT(opcode, label.jumpOperand(offset)));
+    }
+  }
+
   void emitTrap() {
     emitWord(_encode0(Opcode.kTrap));
+    isUnreachable = true;
   }
 
   void emitDrop1() {
@@ -154,40 +174,40 @@
   }
 
   void emitJump(Label label) {
-    emitWord(_encodeT(Opcode.kJump, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJump, label);
+    isUnreachable = true;
   }
 
   void emitJumpIfNoAsserts(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfNoAsserts, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfNoAsserts, label);
   }
 
   void emitJumpIfNotZeroTypeArgs(Label label) {
-    emitWord(
-        _encodeT(Opcode.kJumpIfNotZeroTypeArgs, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfNotZeroTypeArgs, label);
   }
 
   void emitJumpIfEqStrict(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfEqStrict, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfEqStrict, label);
   }
 
   void emitJumpIfNeStrict(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfNeStrict, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfNeStrict, label);
   }
 
   void emitJumpIfTrue(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfTrue, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfTrue, label);
   }
 
   void emitJumpIfFalse(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfFalse, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfFalse, label);
   }
 
   void emitJumpIfNull(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfNull, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfNull, label);
   }
 
   void emitJumpIfNotNull(Label label) {
-    emitWord(_encodeT(Opcode.kJumpIfNotNull, label.jumpOperand(offset)));
+    _emitJumpBytecode(Opcode.kJumpIfNotNull, label);
   }
 
   void patchJump(int pos, int rt) {
@@ -198,6 +218,7 @@
 
   void emitReturnTOS() {
     emitWord(_encode0(Opcode.kReturnTOS));
+    isUnreachable = true;
   }
 
   void emitPush(int rx) {
@@ -306,6 +327,7 @@
 
   void emitThrow(int ra) {
     emitWord(_encodeA(Opcode.kThrow, ra));
+    isUnreachable = true;
   }
 
   void emitEntry(int rd) {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index ad72107..1a95682 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -166,7 +166,7 @@
         _genNativeCall(nativeName);
       } else {
         node.function?.body?.accept(this);
-        // TODO(alexmarkov): figure out when 'return null' should be generated.
+        // BytecodeAssembler eliminates this bytecode if it is unreachable.
         asm.emitPushNull();
       }
       _genReturnTOS();
@@ -624,6 +624,48 @@
     _genJumpIfFalse(!negated, dest);
   }
 
+  /// Returns value of the given expression if it is a bool constant.
+  /// Otherwise, returns `null`.
+  bool _constantConditionValue(Expression condition) {
+    // TODO(dartbug.com/34585): use constant evaluator to evaluate
+    // expressions in a non-constant context.
+    if (condition is Not) {
+      final operand = _constantConditionValue(condition.operand);
+      return (operand != null) ? !operand : null;
+    }
+    if (condition is BoolLiteral) {
+      return condition.value;
+    }
+    Constant constant;
+    if (condition is ConstantExpression) {
+      constant = condition.constant;
+    } else if ((condition is StaticGet && condition.target.isConst) ||
+        (condition is StaticInvocation && condition.isConst) ||
+        (condition is VariableGet && condition.variable.isConst)) {
+      constant = _evaluateConstantExpression(condition);
+    }
+    if (constant is BoolConstant) {
+      return constant.value;
+    }
+    return null;
+  }
+
+  void _genConditionAndJumpIf(Expression condition, bool value, Label dest) {
+    final bool constantValue = _constantConditionValue(condition);
+    if (constantValue != null) {
+      if (constantValue == value) {
+        asm.emitJump(dest);
+      }
+      return;
+    }
+    bool negated = _genCondition(condition);
+    if (value) {
+      _genJumpIfTrue(negated, dest);
+    } else {
+      _genJumpIfFalse(negated, dest);
+    }
+  }
+
   int _getDefaultParamConstIndex(VariableDeclaration param) {
     if (param.initializer == null) {
       return cp.add(const ConstantNull());
@@ -1195,7 +1237,7 @@
 
     function.body.accept(this);
 
-    // TODO(alexmarkov): figure out when 'return null' should be generated.
+    // BytecodeAssembler eliminates this bytecode if it is unreachable.
     asm.emitPushNull();
     _genReturnTOS();
 
@@ -1513,8 +1555,7 @@
     final Label done = new Label();
     final int temp = locals.tempIndexInFrame(node);
 
-    final bool negated = _genCondition(node.condition);
-    _genJumpIfFalse(negated, otherwisePart);
+    _genConditionAndJumpIf(node.condition, false, otherwisePart);
 
     node.then.accept(this);
     asm.emitPopLocal(temp);
@@ -1708,18 +1749,9 @@
     final int temp = locals.tempIndexInFrame(node);
     final isOR = (node.operator == '||');
 
-    bool negated = _genCondition(node.left);
-    if (negated != isOR) {
-      // OR: if (condition == true)
-      // AND: if ((!condition) == true)
-      asm.emitJumpIfTrue(shortCircuit);
-    } else {
-      // OR: if ((!condition) != true)
-      // AND: if (condition != true)
-      asm.emitJumpIfFalse(shortCircuit);
-    }
+    _genConditionAndJumpIf(node.left, isOR, shortCircuit);
 
-    negated = _genCondition(node.right);
+    bool negated = _genCondition(node.right);
     if (negated) {
       asm.emitBooleanNegateTOS();
     }
@@ -2171,8 +2203,7 @@
     final Label done = new Label();
     asm.emitJumpIfNoAsserts(done);
 
-    final bool negated = _genCondition(node.condition);
-    _genJumpIfTrue(negated, done);
+    _genConditionAndJumpIf(node.condition, true, done);
 
     _genPushInt(omitSourcePositions ? 0 : node.conditionStartOffset);
     _genPushInt(omitSourcePositions ? 0 : node.conditionEndOffset);
@@ -2234,16 +2265,20 @@
 
   @override
   visitDoStatement(DoStatement node) {
-    final Label join = new Label();
+    if (asm.isUnreachable) {
+      // Bail out before binding a label which allows backward jumps,
+      // as it is not handled by local unreachable code elimination.
+      return;
+    }
+
+    final Label join = new Label(allowsBackwardJumps: true);
     asm.bind(join);
 
     asm.emitCheckStack();
 
     node.body.accept(this);
 
-    // TODO(alexmarkov): do we need to break this critical edge in CFG?
-    bool negated = _genCondition(node.condition);
-    _genJumpIfTrue(negated, join);
+    _genConditionAndJumpIf(node.condition, true, join);
   }
 
   @override
@@ -2283,8 +2318,14 @@
       _genStoreVar(capturedIteratorVar);
     }
 
+    if (asm.isUnreachable) {
+      // Bail out before binding a label which allows backward jumps,
+      // as it is not handled by local unreachable code elimination.
+      return;
+    }
+
     final Label done = new Label();
-    final Label join = new Label();
+    final Label join = new Label(allowsBackwardJumps: true);
 
     asm.bind(join);
     asm.emitCheckStack();
@@ -2325,37 +2366,44 @@
   @override
   visitForStatement(ForStatement node) {
     _enterScope(node);
+    try {
+      visitList(node.variables, this);
 
-    visitList(node.variables, this);
+      if (asm.isUnreachable) {
+        // Bail out before binding a label which allows backward jumps,
+        // as it is not handled by local unreachable code elimination.
+        return;
+      }
 
-    final Label done = new Label();
-    final Label join = new Label();
-    asm.bind(join);
+      final Label done = new Label();
+      final Label join = new Label(allowsBackwardJumps: true);
+      asm.bind(join);
 
-    asm.emitCheckStack();
+      asm.emitCheckStack();
 
-    if (node.condition != null) {
-      bool negated = _genCondition(node.condition);
-      _genJumpIfFalse(negated, done);
+      if (node.condition != null) {
+        _genConditionAndJumpIf(node.condition, false, done);
+      }
+
+      node.body.accept(this);
+
+      if (locals.currentContextSize > 0) {
+        asm.emitPush(locals.contextVarIndexInFrame);
+        asm.emitCloneContext();
+        asm.emitPopLocal(locals.contextVarIndexInFrame);
+      }
+
+      for (var update in node.updates) {
+        update.accept(this);
+        asm.emitDrop1();
+      }
+
+      asm.emitJump(join);
+
+      asm.bind(done);
+    } finally {
+      _leaveScope();
     }
-
-    node.body.accept(this);
-
-    if (locals.currentContextSize > 0) {
-      asm.emitPush(locals.contextVarIndexInFrame);
-      asm.emitCloneContext();
-      asm.emitPopLocal(locals.contextVarIndexInFrame);
-    }
-
-    for (var update in node.updates) {
-      update.accept(this);
-      asm.emitDrop1();
-    }
-
-    asm.emitJump(join);
-
-    asm.bind(done);
-    _leaveScope();
   }
 
   @override
@@ -2369,8 +2417,7 @@
   visitIfStatement(IfStatement node) {
     final Label otherwisePart = new Label();
 
-    final bool negated = _genCondition(node.condition);
-    _genJumpIfFalse(negated, otherwisePart);
+    _genConditionAndJumpIf(node.condition, false, otherwisePart);
 
     node.then.accept(this);
 
@@ -2431,12 +2478,18 @@
 
     node.expression.accept(this);
 
+    if (asm.isUnreachable) {
+      // Bail out before binding labels which allow backward jumps,
+      // as they are not handled by local unreachable code elimination.
+      return;
+    }
+
     final int temp = locals.tempIndexInFrame(node);
     asm.emitPopLocal(temp);
 
     final Label done = new Label();
-    final List<Label> caseLabels =
-        new List<Label>.generate(node.cases.length, (_) => new Label());
+    final List<Label> caseLabels = new List<Label>.generate(
+        node.cases.length, (_) => new Label(allowsBackwardJumps: true));
     final equalsArgDesc = cp.add(new ConstantArgDesc(2));
 
     Label defaultLabel = done;
@@ -2550,6 +2603,9 @@
     tryBlock.endPC = asm.offsetInWords;
     tryBlock.handlerPC = asm.offsetInWords;
 
+    // Exception handlers are reachable although there are no labels or jumps.
+    asm.isUnreachable = false;
+
     asm.emitSetFrame(locals.frameSize);
 
     _restoreContextForTryBlock(node);
@@ -2594,6 +2650,10 @@
 
   @override
   visitTryCatch(TryCatch node) {
+    if (asm.isUnreachable) {
+      return;
+    }
+
     final Label done = new Label();
 
     final TryBlock tryBlock = _startTryBlock(node);
@@ -2660,17 +2720,22 @@
 
   @override
   visitTryFinally(TryFinally node) {
+    if (asm.isUnreachable) {
+      return;
+    }
+
     final TryBlock tryBlock = _startTryBlock(node);
     finallyBlocks[node] = <FinallyBlock>[];
 
     node.body.accept(this);
 
-    // TODO(alexmarkov): Do not generate normal continuation if control
-    // does not return from body.
-    final normalContinuation =
-        new FinallyBlock(() {/* do nothing (fall through) */});
-    finallyBlocks[node].add(normalContinuation);
-    asm.emitJump(normalContinuation.entry);
+    if (!asm.isUnreachable) {
+      final normalContinuation = new FinallyBlock(() {
+        /* do nothing (fall through) */
+      });
+      finallyBlocks[node].add(normalContinuation);
+      asm.emitJump(normalContinuation.entry);
+    }
 
     _endTryBlock(node, tryBlock);
 
@@ -2716,14 +2781,19 @@
 
   @override
   visitWhileStatement(WhileStatement node) {
+    if (asm.isUnreachable) {
+      // Bail out before binding a label which allows backward jumps,
+      // as it is not handled by local unreachable code elimination.
+      return;
+    }
+
     final Label done = new Label();
-    final Label join = new Label();
+    final Label join = new Label(allowsBackwardJumps: true);
     asm.bind(join);
 
     asm.emitCheckStack();
 
-    bool negated = _genCondition(node.condition);
-    _genJumpIfFalse(negated, done);
+    _genConditionAndJumpIf(node.condition, false, done);
 
     node.body.accept(this);
 
@@ -2738,9 +2808,13 @@
       throw 'YieldStatement must be desugared: $node';
     }
 
+    if (asm.isUnreachable) {
+      return;
+    }
+
     // 0 is reserved for normal entry, yield points are counted from 1.
     final int yieldIndex = yieldPoints.length + 1;
-    final Label continuationLabel = new Label();
+    final Label continuationLabel = new Label(allowsBackwardJumps: true);
     yieldPoints.add(continuationLabel);
 
     // :await_jump_var = #index
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 5a5cd62..7b37aaa 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -120,7 +120,6 @@
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L3
 Try #0 end:
 Try #0 handler:
   SetFrame             10
@@ -243,8 +242,6 @@
   LoadContextVar       1
   InstanceCall         1, CP#34
   ReturnTOS
-  PushNull
-  ReturnTOS
 
 }
 ]static field (asy::Future<core::int>) → asy::Future<core::Null> asyncInFieldInitializer = (asy::Future<core::int> x) → asy::Future<core::Null> /* originally async */ {
@@ -340,11 +337,6 @@
   LoadContextVar       0
   InstanceCall         1, CP#28
   ReturnTOS
-  Push                 r0
-  LoadContextParent
-  PopLocal             r0
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
@@ -409,7 +401,6 @@
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L3
 Try #0 end:
 Try #0 handler:
   SetFrame             10
@@ -548,8 +539,6 @@
   LoadContextVar       2
   InstanceCall         1, CP#32
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
@@ -677,7 +666,6 @@
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L5
 Try #0 end:
 Try #0 handler:
   SetFrame             10
@@ -831,8 +819,6 @@
   LoadContextVar       1
   InstanceCall         1, CP#37
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
@@ -1076,9 +1062,6 @@
   LoadContextParent
   PopLocal             r4
   Jump                 L9
-  Push                 r4
-  LoadContextParent
-  PopLocal             r4
 L9:
   Push                 r4
   LoadContextVar       1
@@ -1089,7 +1072,6 @@
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L10
 Try #0 end:
 Try #0 handler:
   SetFrame             11
@@ -1265,8 +1247,6 @@
   LoadContextVar       3
   InstanceCall         1, CP#45
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
@@ -1484,8 +1464,6 @@
   LoadContextParent
   LoadContextVar       13
   Throw                1
-  Drop1
-  Jump                 L3
 L3:
   Jump                 L7
 Try #1 end:
@@ -1564,13 +1542,6 @@
   LoadContextParent
   PopLocal             r4
   Jump                 L9
-  Push                 r4
-  LoadContextParent
-  LoadContextVar       12
-  Push                 r4
-  LoadContextParent
-  LoadContextVar       13
-  Throw                1
 L5:
   Push                 r0
   LoadFieldTOS         CP#5
@@ -1635,10 +1606,6 @@
   LoadContextParent
   PopLocal             r4
   Jump                 L9
-  Push                 r4
-  LoadContextParent
-  PopLocal             r4
-  Jump                 L9
 L7:
   Push                 r0
   LoadFieldTOS         CP#5
@@ -1703,9 +1670,6 @@
   LoadContextParent
   PopLocal             r4
   Jump                 L9
-  Push                 r4
-  LoadContextParent
-  PopLocal             r4
 L9:
   Push                 r4
   LoadContextVar       3
@@ -1716,7 +1680,6 @@
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L12
 Try #0 end:
 Try #0 handler:
   SetFrame             14
@@ -1829,28 +1792,26 @@
   Push                 r0
   PushInt              3
   StoreContextVar      1
-  Allocate             CP#20
+  Allocate             CP#19
   StoreLocal           r3
   Push                 r3
   PushNull
-  StoreFieldTOS        CP#21
+  StoreFieldTOS        CP#20
   Push                 r3
   PushNull
-  StoreFieldTOS        CP#23
+  StoreFieldTOS        CP#22
   Push                 r3
-  PushConstant         CP#25
-  StoreFieldTOS        CP#26
+  PushConstant         CP#24
+  StoreFieldTOS        CP#25
   Push                 r3
   PushConstant         CP#0
-  StoreFieldTOS        CP#28
+  StoreFieldTOS        CP#27
   Push                 r3
   Push                 r0
   StoreFieldTOS        CP#1
   PopLocal             r2
   Push                 r2
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ClosureFunction nested () → dart.async::Future<dart.core::int> /* originally async */ ;
@@ -1867,29 +1828,28 @@
   [11] = String 'fin'
   [12] = StaticICData target 'dart.core::print', arg-desc CP#4
   [13] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [14] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [15] = ArgDesc num-args 2, num-type-args 0, names []
-  [16] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#15
-  [17] = ArgDesc num-args 3, num-type-args 0, names []
-  [18] = ICData target-name 'completeError', arg-desc CP#17
-  [19] = EndClosureFunctionScope
-  [20] = Class dart.core::_Closure
-  [21] = InstanceField dart.core::_Closure::_instantiator_type_arguments
-  [22] = Reserved
-  [23] = InstanceField dart.core::_Closure::_function_type_arguments
-  [24] = Reserved
-  [25] = EmptyTypeArguments
-  [26] = InstanceField dart.core::_Closure::_delayed_type_arguments
-  [27] = Reserved
-  [28] = InstanceField dart.core::_Closure::_function
-  [29] = Reserved
-  [30] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#4
-  [31] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#4
-  [32] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#4
-  [33] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [34] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#15
-  [35] = ICData get target-name 'future', arg-desc CP#4
-  [36] = EndClosureFunctionScope
+  [14] = ArgDesc num-args 2, num-type-args 0, names []
+  [15] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#14
+  [16] = ArgDesc num-args 3, num-type-args 0, names []
+  [17] = ICData target-name 'completeError', arg-desc CP#16
+  [18] = EndClosureFunctionScope
+  [19] = Class dart.core::_Closure
+  [20] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [21] = Reserved
+  [22] = InstanceField dart.core::_Closure::_function_type_arguments
+  [23] = Reserved
+  [24] = EmptyTypeArguments
+  [25] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [26] = Reserved
+  [27] = InstanceField dart.core::_Closure::_function
+  [28] = Reserved
+  [29] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#4
+  [30] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#4
+  [31] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#4
+  [32] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
+  [33] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#14
+  [34] = ICData get target-name 'future', arg-desc CP#4
+  [35] = EndClosureFunctionScope
 }
 Closure CP#6 {
   EntryOptional        1, 3, 0
@@ -1955,7 +1915,7 @@
   PopLocal             r11
   PushNull
   ReturnTOS
-L7:
+L6:
   Push                 r2
   JumpIfNull           L2
   Push                 r2
@@ -1976,7 +1936,6 @@
   AddInt
   StoreContextVar      1
   Jump                 L3
-  Jump                 L4
 Try #1 end:
 Try #1 handler:
   SetFrame             12
@@ -2009,32 +1968,17 @@
   Push                 r4
   LoadContextParent
   PopLocal             r4
-  Jump                 L5
+  Jump                 L4
 L4:
-  Push                 r0
-  LoadFieldTOS         CP#1
-  PopLocal             r4
-  Push                 r4
-  LoadContextVar       7
-  PopLocal             r4
-  PushConstant         CP#11
-  PushConstant         CP#14
-  IndirectStaticCall   1, CP#4
-  Drop1
-  Push                 r4
-  LoadContextParent
-  PopLocal             r4
-L5:
   Push                 r4
   LoadContextVar       0
   Push                 r4
   LoadContextVar       1
-  PushConstant         CP#16
-  IndirectStaticCall   2, CP#15
+  PushConstant         CP#15
+  IndirectStaticCall   2, CP#14
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L6
 Try #0 end:
 Try #0 handler:
   SetFrame             12
@@ -2054,17 +1998,17 @@
   LoadContextVar       0
   Push                 r8
   Push                 r9
-  InstanceCall         3, CP#18
+  InstanceCall         3, CP#17
   Drop1
-  Jump                 L6
-L6:
+  Jump                 L5
+L5:
   PushNull
   ReturnTOS
 L1:
   Push                 r4
   LoadContextVar       5
   PopLocal             r4
-  Jump                 L7
+  Jump                 L6
 
 }
 
@@ -2109,55 +2053,50 @@
   PushNull
   StoreContextVar      7
   Push                 r0
-  Allocate             CP#20
+  Allocate             CP#19
   StoreLocal           r3
   Push                 r3
   PushNull
-  StoreFieldTOS        CP#21
+  StoreFieldTOS        CP#20
   Push                 r3
   PushNull
-  StoreFieldTOS        CP#23
+  StoreFieldTOS        CP#22
   Push                 r3
-  PushConstant         CP#25
-  StoreFieldTOS        CP#26
+  PushConstant         CP#24
+  StoreFieldTOS        CP#25
   Push                 r3
   PushConstant         CP#6
-  StoreFieldTOS        CP#28
+  StoreFieldTOS        CP#27
   Push                 r3
   Push                 r0
   StoreFieldTOS        CP#1
   StoreContextVar      8
   Push                 r0
   LoadContextVar       8
-  PushConstant         CP#30
+  PushConstant         CP#29
   IndirectStaticCall   1, CP#4
   PopLocal             r2
   Push                 r0
   Push                 r0
   LoadContextVar       8
-  PushConstant         CP#31
+  PushConstant         CP#30
   IndirectStaticCall   1, CP#4
   StoreContextVar      2
   Push                 r0
   Push                 r0
   LoadContextVar       8
-  PushConstant         CP#32
+  PushConstant         CP#31
   IndirectStaticCall   1, CP#4
   StoreContextVar      3
-  PushConstant         CP#33
+  PushConstant         CP#32
   Push                 r0
   LoadContextVar       8
-  PushConstant         CP#34
-  IndirectStaticCall   2, CP#15
+  PushConstant         CP#33
+  IndirectStaticCall   2, CP#14
   Drop1
   Push                 r0
   LoadContextVar       0
-  InstanceCall         1, CP#35
-  ReturnTOS
-  Push                 r0
-  LoadContextParent
-  PopLocal             r0
-  PushNull
+  InstanceCall         1, CP#34
   ReturnTOS
 
 }
@@ -2283,8 +2222,6 @@
   LoadContextVar       1
   InstanceCall         1, CP#32
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
@@ -2394,7 +2331,6 @@
   Drop1
   PushNull
   ReturnTOS
-  Jump                 L5
 Try #0 end:
 Try #0 handler:
   SetFrame             10
diff --git a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
index 5711186..c47aadf 100644
--- a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
+++ b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
@@ -136,8 +136,6 @@
   PushConstant         CP#0
   PushStatic           CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = StaticField #lib::_NamespaceImpl::_cachedNamespace
@@ -164,8 +162,6 @@
   PushConstant         CP#3
   IndirectStaticCall   1, CP#2
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 0, num-type-args 0, names []
@@ -220,8 +216,6 @@
   PushConstant         CP#1
   IndirectStaticCall   0, CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 0, num-type-args 0, names []
@@ -236,8 +230,6 @@
   PushConstant         CP#1
   IndirectStaticCall   0, CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 0, num-type-args 0, names []
@@ -326,8 +318,6 @@
   PushConstant         CP#0
   PushStatic           CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = StaticField #lib::VMLibraryHooks::_cachedScript
@@ -385,8 +375,6 @@
   CheckStack
   PushConstant         CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TearOff #lib::_print
@@ -474,7 +462,6 @@
   PushConstant         CP#9
   IndirectStaticCall   1, CP#8
   ReturnTOS
-  Jump                 L6
 L5:
   PushConstant         CP#11
   IndirectStaticCall   0, CP#10
@@ -485,9 +472,6 @@
   IndirectStaticCall   2, CP#2
   InstanceCall         2, CP#13
   ReturnTOS
-L6:
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = StaticField #lib::_rawScript
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index e7acb3d..d73647e 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -936,8 +936,6 @@
   LoadContextVar       0
   AddInt
   ReturnTOS
-  PushNull
-  ReturnTOS
 
 }
 
@@ -1131,8 +1129,6 @@
   Push                 r0
   StoreFieldTOS        CP#5
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Type #lib::D::T
@@ -1163,8 +1159,6 @@
   Push                 r0
   LoadContextVar       0
   ReturnTOS
-  PushNull
-  ReturnTOS
 
 }
 ]  method foo(generic-covariant-impl self::D::T t) → dynamic {
@@ -1205,11 +1199,6 @@
   Push                 r0
   LoadContextVar       0
   ReturnTOS
-  Push                 r0
-  LoadContextParent
-  PopLocal             r0
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ClosureFunction <anonymous closure> (dart.core::int y) → dart.core::Null;
@@ -1461,8 +1450,6 @@
   PopLocal             r4
   Push                 r4
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ClosureFunction foo <T extends dart.core::Object = dynamic>(T t) → void;
diff --git a/pkg/vm/testcases/bytecode/deferred_lib.dart.expect b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
index d0261e3..67139cb 100644
--- a/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
+++ b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
@@ -13,8 +13,6 @@
   PushConstant         CP#3
   IndirectStaticCall   0, CP#2
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -32,8 +30,6 @@
   PushConstant         CP#1
   IndirectStaticCall   1, CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart.expect b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
index 1f0cfa2..1cd0231 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart.expect
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
@@ -200,8 +200,6 @@
   PushConstant         CP#2
   IndirectStaticCall   1, CP#1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsField #lib::E
@@ -239,8 +237,6 @@
   PushConstant         CP#2
   IndirectStaticCall   1, CP#1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsField #lib::F
@@ -284,8 +280,6 @@
   IndirectStaticCall   1, CP#2
   Drop1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Class #lib::H
@@ -350,8 +344,6 @@
   IndirectStaticCall   2, CP#3
   Drop1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = String 'param'
@@ -392,8 +384,6 @@
   IndirectStaticCall   1, CP#1
   Drop1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Class #lib::TestTypeArgReuse
@@ -435,8 +425,6 @@
   IndirectStaticCall   2, CP#2
   Drop1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Class #lib::C
@@ -569,8 +557,6 @@
   PushConstant         CP#2
   IndirectStaticCall   2, CP#1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.core::_GrowableList [dart.core::String]
@@ -588,8 +574,6 @@
   PushConstant         CP#2
   IndirectStaticCall   2, CP#1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation dart.core::_List [dart.core::int]
diff --git a/pkg/vm/testcases/bytecode/literals.dart.expect b/pkg/vm/testcases/bytecode/literals.dart.expect
index 0954a1f..e5ace82 100644
--- a/pkg/vm/testcases/bytecode/literals.dart.expect
+++ b/pkg/vm/testcases/bytecode/literals.dart.expect
@@ -122,8 +122,6 @@
   PushConstant         CP#1
   IndirectStaticCall   1, CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -693,8 +691,6 @@
   CheckStack
   PushConstant         CP#1
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsForInstanceAllocation #lib::F [dart.core::int, dart.core::String]
@@ -708,8 +704,6 @@
   CheckStack
   PushConstant         CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Type <X extends dart.core::Object = dynamic>(X) → X
@@ -723,8 +717,6 @@
   PushConstant         CP#0
   PushStatic           CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = StaticField #lib::fieldWithDoubleLiteralInitializer
diff --git a/pkg/vm/testcases/bytecode/loops.dart.expect b/pkg/vm/testcases/bytecode/loops.dart.expect
index 913c397..3c0804e 100644
--- a/pkg/vm/testcases/bytecode/loops.dart.expect
+++ b/pkg/vm/testcases/bytecode/loops.dart.expect
@@ -33,8 +33,6 @@
 L1:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -87,8 +85,6 @@
 L1:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -147,8 +143,6 @@
 L1:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -201,8 +195,6 @@
 L1:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -246,8 +238,6 @@
   JumpIfTrue           L1
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
@@ -290,8 +280,6 @@
 L1:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -335,8 +323,6 @@
 L1:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
diff --git a/pkg/vm/testcases/bytecode/super_calls.dart.expect b/pkg/vm/testcases/bytecode/super_calls.dart.expect
index 7c6b17e..f466a6d 100644
--- a/pkg/vm/testcases/bytecode/super_calls.dart.expect
+++ b/pkg/vm/testcases/bytecode/super_calls.dart.expect
@@ -38,8 +38,6 @@
   CheckStack
   PushInt              42
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
 }
@@ -86,8 +84,6 @@
   PushConstant         CP#3
   IndirectStaticCall   4, CP#2
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgs [dart.core::String]
@@ -105,8 +101,6 @@
   PushConstant         CP#1
   IndirectStaticCall   1, CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -122,8 +116,6 @@
   PushConstant         CP#1
   IndirectStaticCall   1, CP#0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
@@ -142,8 +134,6 @@
   PushConstant         CP#3
   InstanceCall         3, CP#5
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgs [dart.core::int]
@@ -254,8 +244,6 @@
   PushConstant         CP#9
   IndirectStaticCall   2, CP#8
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = String 'foo'
@@ -292,8 +280,6 @@
   PushConstant         CP#6
   IndirectStaticCall   2, CP#5
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = String 'foo'
@@ -327,8 +313,6 @@
   PushConstant         CP#6
   IndirectStaticCall   2, CP#5
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = String 'bar'
@@ -365,8 +349,6 @@
   PushConstant         CP#8
   InstanceCall         3, CP#10
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgs [dart.core::int]
diff --git a/pkg/vm/testcases/bytecode/switch.dart.expect b/pkg/vm/testcases/bytecode/switch.dart.expect
index 6fd01d5..bb4fbbb 100644
--- a/pkg/vm/testcases/bytecode/switch.dart.expect
+++ b/pkg/vm/testcases/bytecode/switch.dart.expect
@@ -38,8 +38,6 @@
 L4:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
@@ -119,8 +117,6 @@
 L4:
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
@@ -206,8 +202,6 @@
   PopLocal             r0
   Push                 r0
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index ac93137..e513f1e 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -325,7 +325,6 @@
   PopLocal             r6
   Push                 r6
   ReturnTOS
-  Jump                 L1
 L1:
   Push                 r0
   LoadContextParent
@@ -533,7 +532,6 @@
   Push                 r2
   Push                 r3
   Throw                1
-  Drop1
 L2:
   Jump                 L3
 Try #2 end:
@@ -575,9 +573,9 @@
   ReturnTOS
 }
 ExceptionsTable {
-  try-index 0, outer -1, start 2, end 36, handler 36, needs-stack-trace, types [CP#3]
+  try-index 0, outer -1, start 2, end 35, handler 35, needs-stack-trace, types [CP#3]
   try-index 1, outer 0, start 2, end 7, handler 7, needs-stack-trace, types [CP#3]
-  try-index 2, outer 0, start 12, end 24, handler 24, types [CP#3]
+  try-index 2, outer 0, start 12, end 23, handler 23, types [CP#3]
 }
 ConstantPool {
   [0] = String 'try 1 > try 2'
@@ -753,7 +751,6 @@
   InstanceCall         1, CP#24
   Drop1
   Jump                 L4
-  Jump                 L5
 Try #1 end:
 Try #1 handler:
   SetFrame             9
@@ -775,19 +772,7 @@
   PushConstant         CP#28
   IndirectStaticCall   1, CP#4
   Drop1
-  Jump                 L6
-L5:
-  Push                 r5
-  PopLocal             r0
-  PushConstant         CP#26
-  PushConstant         CP#29
-  IndirectStaticCall   1, CP#4
-  Drop1
-  PushConstant         CP#30
-  PushConstant         CP#31
-  IndirectStaticCall   1, CP#4
-  Drop1
-  Jump                 L7
+  Jump                 L5
 Try #0 end:
 Try #0 handler:
   SetFrame             9
@@ -795,32 +780,24 @@
   PopLocal             r0
   MoveSpecial          r3, exception
   MoveSpecial          r4, stackTrace
+  PushConstant         CP#31
   PushConstant         CP#32
-  PushConstant         CP#33
   IndirectStaticCall   1, CP#4
   Drop1
   Push                 r3
   Push                 r4
   Throw                1
-L6:
+L5:
   Push                 r3
   PopLocal             r0
-  PushConstant         CP#32
-  PushConstant         CP#34
+  PushConstant         CP#31
+  PushConstant         CP#33
   IndirectStaticCall   1, CP#4
   Drop1
   Jump                 L2
-L7:
-  Push                 r3
-  PopLocal             r0
-  PushConstant         CP#32
-  PushConstant         CP#35
-  IndirectStaticCall   1, CP#4
-  Drop1
-  Jump                 L3
 L2:
-  PushConstant         CP#36
-  PushConstant         CP#37
+  PushConstant         CP#34
+  PushConstant         CP#35
   IndirectStaticCall   1, CP#4
   Drop1
   Jump                 L3
@@ -829,8 +806,8 @@
   ReturnTOS
 }
 ExceptionsTable {
-  try-index 0, outer -1, start 21, end 87, handler 87, needs-stack-trace, types [CP#25]
-  try-index 1, outer 0, start 30, end 57, handler 57, needs-stack-trace, types [CP#25]
+  try-index 0, outer -1, start 21, end 75, handler 75, needs-stack-trace, types [CP#25]
+  try-index 1, outer 0, start 30, end 56, handler 56, needs-stack-trace, types [CP#25]
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
@@ -862,15 +839,13 @@
   [26] = String 'finally 1'
   [27] = StaticICData target 'dart.core::print', arg-desc CP#4
   [28] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [29] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [30] = String 'after try 1'
-  [31] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [32] = String 'finally 2'
+  [29] = String 'after try 1'
+  [30] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [31] = String 'finally 2'
+  [32] = StaticICData target 'dart.core::print', arg-desc CP#4
   [33] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [34] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [34] = String 'case 2'
   [35] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [36] = String 'case 2'
-  [37] = StaticICData target 'dart.core::print', arg-desc CP#4
 }
 Closure CP#8 {
   EntryFixed           1, 2
@@ -942,20 +917,20 @@
   Push                 r0
   PopLocal             r3
 Try #0 start:
-  Allocate             CP#22
+  Allocate             CP#16
   StoreLocal           r5
   Push                 r5
   PushNull
-  StoreFieldTOS        CP#23
+  StoreFieldTOS        CP#17
   Push                 r5
   PushNull
-  StoreFieldTOS        CP#25
+  StoreFieldTOS        CP#19
   Push                 r5
-  PushConstant         CP#27
-  StoreFieldTOS        CP#28
+  PushConstant         CP#21
+  StoreFieldTOS        CP#22
   Push                 r5
   PushConstant         CP#0
-  StoreFieldTOS        CP#30
+  StoreFieldTOS        CP#24
   Push                 r5
   Push                 r0
   StoreFieldTOS        CP#1
@@ -970,11 +945,11 @@
   MoveSpecial          r4, stackTrace
   Push                 r0
   LoadContextVar       0
-  PushConstant         CP#32
+  PushConstant         CP#26
   IndirectStaticCall   1, CP#3
   Drop1
   Push                 r2
-  InstanceCall         1, CP#33
+  InstanceCall         1, CP#27
   Drop1
   Push                 r3
   Push                 r4
@@ -984,11 +959,11 @@
   PopLocal             r0
   Push                 r0
   LoadContextVar       0
-  PushConstant         CP#34
+  PushConstant         CP#28
   IndirectStaticCall   1, CP#3
   Drop1
   Push                 r2
-  InstanceCall         1, CP#35
+  InstanceCall         1, CP#29
   Drop1
   Push                 r0
   LoadContextParent
@@ -1015,27 +990,21 @@
   [12] = StaticICData target 'dart.core::print', arg-desc CP#3
   [13] = StaticICData target 'dart.core::print', arg-desc CP#3
   [14] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [15] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [16] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [17] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [18] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [19] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [20] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [21] = EndClosureFunctionScope
-  [22] = Class dart.core::_Closure
-  [23] = InstanceField dart.core::_Closure::_instantiator_type_arguments
-  [24] = Reserved
-  [25] = InstanceField dart.core::_Closure::_function_type_arguments
-  [26] = Reserved
-  [27] = EmptyTypeArguments
-  [28] = InstanceField dart.core::_Closure::_delayed_type_arguments
-  [29] = Reserved
-  [30] = InstanceField dart.core::_Closure::_function
-  [31] = Reserved
-  [32] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [33] = ICData dynamic target-name 'call', arg-desc CP#3
-  [34] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [35] = ICData dynamic target-name 'call', arg-desc CP#3
+  [15] = EndClosureFunctionScope
+  [16] = Class dart.core::_Closure
+  [17] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [18] = Reserved
+  [19] = InstanceField dart.core::_Closure::_function_type_arguments
+  [20] = Reserved
+  [21] = EmptyTypeArguments
+  [22] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [23] = Reserved
+  [24] = InstanceField dart.core::_Closure::_function
+  [25] = Reserved
+  [26] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [27] = ICData dynamic target-name 'call', arg-desc CP#3
+  [28] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [29] = ICData dynamic target-name 'call', arg-desc CP#3
 }
 Closure CP#0 {
   EntryFixed           1, 6
@@ -1056,7 +1025,6 @@
   IndirectStaticCall   1, CP#3
   Drop1
   Jump                 L1
-  Jump                 L2
 Try #0 end:
 Try #0 handler:
   SetFrame             6
@@ -1071,8 +1039,7 @@
   PushConstant         CP#9
   IndirectStaticCall   1, CP#3
   Drop1
-  Jump                 L3
-  Jump                 L4
+  Jump                 L2
 Try #1 end:
 Try #1 handler:
   SetFrame             6
@@ -1088,7 +1055,7 @@
   Push                 r4
   Push                 r5
   Throw                1
-L3:
+L2:
   Push                 r4
   PopLocal             r0
   Push                 r0
@@ -1098,17 +1065,6 @@
   Drop1
   PushInt              43
   ReturnTOS
-L4:
-  Push                 r4
-  PopLocal             r0
-  Push                 r0
-  LoadContextVar       0
-  PushConstant         CP#12
-  IndirectStaticCall   1, CP#3
-  Drop1
-  Push                 r2
-  Push                 r3
-  Throw                1
 L1:
   Push                 r2
   PopLocal             r0
@@ -1116,11 +1072,10 @@
   PopLocal             r4
 Try #2 start:
   PushConstant         CP#8
-  PushConstant         CP#13
+  PushConstant         CP#12
   IndirectStaticCall   1, CP#3
   Drop1
-  Jump                 L5
-  Jump                 L6
+  Jump                 L3
 Try #2 end:
 Try #2 handler:
   SetFrame             6
@@ -1130,79 +1085,22 @@
   MoveSpecial          r5, stackTrace
   Push                 r0
   LoadContextVar       0
+  PushConstant         CP#13
+  IndirectStaticCall   1, CP#3
+  Drop1
+  Push                 r4
+  Push                 r5
+  Throw                1
+L3:
+  Push                 r4
+  PopLocal             r0
+  Push                 r0
+  LoadContextVar       0
   PushConstant         CP#14
   IndirectStaticCall   1, CP#3
   Drop1
-  Push                 r4
-  Push                 r5
-  Throw                1
-L5:
-  Push                 r4
-  PopLocal             r0
-  Push                 r0
-  LoadContextVar       0
-  PushConstant         CP#15
-  IndirectStaticCall   1, CP#3
-  Drop1
   PushInt              43
   ReturnTOS
-L6:
-  Push                 r4
-  PopLocal             r0
-  Push                 r0
-  LoadContextVar       0
-  PushConstant         CP#16
-  IndirectStaticCall   1, CP#3
-  Drop1
-  PushInt              42
-  ReturnTOS
-L2:
-  Push                 r2
-  PopLocal             r0
-  Push                 r0
-  PopLocal             r4
-Try #3 start:
-  PushConstant         CP#8
-  PushConstant         CP#17
-  IndirectStaticCall   1, CP#3
-  Drop1
-  Jump                 L7
-  Jump                 L8
-Try #3 end:
-Try #3 handler:
-  SetFrame             6
-  Push                 r4
-  PopLocal             r0
-  MoveSpecial          r4, exception
-  MoveSpecial          r5, stackTrace
-  Push                 r0
-  LoadContextVar       0
-  PushConstant         CP#18
-  IndirectStaticCall   1, CP#3
-  Drop1
-  Push                 r4
-  Push                 r5
-  Throw                1
-L7:
-  Push                 r4
-  PopLocal             r0
-  Push                 r0
-  LoadContextVar       0
-  PushConstant         CP#19
-  IndirectStaticCall   1, CP#3
-  Drop1
-  PushInt              43
-  ReturnTOS
-L8:
-  Push                 r4
-  PopLocal             r0
-  Push                 r0
-  LoadContextVar       0
-  PushConstant         CP#20
-  IndirectStaticCall   1, CP#3
-  Drop1
-  PushNull
-  ReturnTOS
 
 }
 ]static method testTryFinally3() → dynamic {
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index c718bdb..ef13709 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -206,8 +206,6 @@
   AssertAssignable     0, CP#13
   InstanceCall         1, CP#14
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Type #lib::A<#lib::D::foo3::T1>
@@ -269,8 +267,6 @@
   PushConstant         CP#3
   AssertAssignable     0, CP#7
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = TypeArgumentsField #lib::D
@@ -294,8 +290,6 @@
   CheckStack
   PushNull
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
 }
@@ -366,8 +360,6 @@
   PushConstant         CP#12
   AssertAssignable     0, CP#13
   ReturnTOS
-  PushNull
-  ReturnTOS
 }
 ConstantPool {
   [0] = Type #lib::B
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index d5ac9d0..6d48c90 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -1011,8 +1011,17 @@
 }
 
 void BytecodeFlowGraphBuilder::BuildJumpIfNoAsserts() {
+  ASSERT(B->stack_ == nullptr);
   if (!isolate()->asserts()) {
     BuildJump();
+    // Skip all instructions up to the target PC, as they are all unreachable.
+    // If not skipped, some of the assert code may be considered reachable
+    // (if it contains jumps) and generated. The problem is that generated
+    // code may expect values left on the stack from unreachable
+    // (and not generated) code which immediately follows this Jump.
+    const intptr_t target_pc = pc_ + DecodeOperandT().value();
+    ASSERT(target_pc > pc_);
+    pc_ = target_pc - 1;
   }
 }
 
@@ -1107,6 +1116,7 @@
   LoadStackSlots(1);
   ASSERT(code_.is_open());
   code_ += B->Return(position_);
+  ASSERT(B->stack_ == nullptr);
 }
 
 void BytecodeFlowGraphBuilder::BuildTrap() {
@@ -1419,6 +1429,9 @@
         handler_info.handler_pc_offset, /* is_return_address = */ false);
     JoinEntryInstr* join = EnsureControlFlowJoin(descriptors, handler_pc);
 
+    // Make sure exception handler starts with SetFrame bytecode instruction.
+    InstructionAt(handler_pc, KernelBytecode::kSetFrame);
+
     const Array& handler_types =
         Array::ZoneHandle(Z, handlers.GetHandledTypes(try_index));
 
@@ -1476,9 +1489,9 @@
       }
       code_ = Fragment(join);
       B->SetCurrentTryIndex(join->try_index());
-    } else if (code_.is_closed()) {
-      // Skip unreachable bytecode instructions.
-      continue;
+    } else {
+      // Unreachable bytecode is not allowed.
+      ASSERT(!code_.is_closed());
     }
 
     BuildInstruction(KernelBytecode::DecodeOpcode(bytecode_instr_));