anchor.diff:        }
       }
       Uint8List candidate = builder.takeBytes();
  -    if (!await crashesOnCompile(
  -        fs, main, candidate, compilerContext, initialComponent)) {
  -      // Didn't crash => Can't remove line i.
  -      include[i] = true;
  +    fs.data[uri] = candidate;
  +    if (!await crashesOnCompile(initialComponent)) {
  +      // Didn't crash => Can't remove line i-j.
  +      for (int j = i; j < i + length; j++) {
  +        include[j] = true;
  +      }
  +      if (length > 2) {
  +        // Retry with length 2 at same i.
  +        // The idea here is that for instance formatted json might have lines
  +        // looking like
  +        // {
  +        // }
  +        // where deleting just one line makes it invalid.
  +        length = 2;
  +      } else if (length > 1) {
  +        // Retry with length 1 at same i.
  +        length = 1;
  +      } else {
  +        // Couldn't with length 1 either.
  +        i++;
  +      }
       } else {
  -      print("Can delete line $i");
  +      print("Can delete line $i (inclusive) - ${i + length} (exclusive) "
  +          "(of ${lines.length})");
         latestCrashData = candidate;
  -    }
  -  }
  -  return latestCrashData;
  -}
  -
  -Future<bool> crashesOnCompile(MemoryFileSystem fs, Uri main, Uint8List data,
  -    CompilerContext compilerContext, Component initialComponent) async {
  -  fs.entityForUri(main).writeAsBytesSync(data);
  +      i += length;
  +      length *= 2;
  +    }
  +  }
  +  fs.data[uri] = latestCrashData;
  +}
  +
  +Component _latestComponent;
  +
  +Future<bool> crashesOnCompile(Component initialComponent) async {
     IncrementalCompiler incrementalCompiler =
  -      new IncrementalCompiler.fromComponent(compilerContext, initialComponent);
  -  incrementalCompiler.invalidate(main);
  +      new IncrementalCompiler.fromComponent(
  +          setupCompilerContext(), initialComponent);
  +  incrementalCompiler.invalidate(mainUri);
     try {
  -    await incrementalCompiler.computeDelta();
  +    _latestComponent = await incrementalCompiler.computeDelta();
  +    for (Uri uri in invalidate) {
  +      incrementalCompiler.invalidate(uri);
  +      await incrementalCompiler.computeDelta();
  +    }
       return false;
  -  } catch (e) {
  -    return true;
  -  }
  -}
  -
  -Future<Component> getInitialComponent(CompilerContext compilerContext) async {
  +  } catch (e, st) {
  +    // Find line with #0 in it.
  +    String eWithSt = "$e\n\n$st";
  +    List<String> lines = eWithSt.split("\n");
  +    String foundLine;
  +    for (String line in lines) {
  +      if (line.startsWith("#0")) {
  +        foundLine = line;
  +        break;
  +      }
  +    }
  +    if (foundLine == null) throw "Unexpected crash without stacktrace: $e";
  +    if (expectedCrashLine == null) {
  +      print("Got $foundLine");
  +      expectedCrashLine = foundLine;
  +      return true;
  +    } else if (foundLine == expectedCrashLine) {
  +      return true;
  +    } else {
  +      print("Crashed, but another place: $foundLine");
  +      return false;
  +    }
  +  }
  +}
  +
  +Future<Component> getInitialComponent() async {
     IncrementalCompiler incrementalCompiler =
  -      new IncrementalCompiler(compilerContext);
  +      new IncrementalCompiler(setupCompilerContext());
     Component originalComponent = await incrementalCompiler.computeDelta();
     return originalComponent;
   }
   
  -CompilerContext setupCompilerContext(Uri main) {
  -  Uint8List sdkSummaryData = new File.fromUri(platformUri).readAsBytesSync();
  -  MemoryFileSystem fs = new MemoryFileSystem(base);
  +CompilerContext setupCompilerContext() {
     CompilerOptions options = getOptions();
   
  +  TargetFlags targetFlags = new TargetFlags(
  +      enableNullSafety: nnbd, trackWidgetCreation: widgetTransformation);
  +  Target target;
  +  switch (targetString) {
  +    case "VM":
  +      target = new VmTarget(targetFlags);
  +      break;
  +    case "flutter":
  +      target = new FlutterTarget(targetFlags);
  +      break;
  +    case "ddc":
  +      target = new DevCompilerTarget(targetFlags);
  +      break;
  +    default:
  +      throw "Unknown target '$target'";
  +  }
  +  options.target = target;
     options.fileSystem = fs;
     options.sdkRoot = null;
  -  options.sdkSummary = sdkSummary;
  +  options.sdkSummary = platformUri;
     options.omitPlatform = false;
     options.onDiagnostic = (DiagnosticMessage message) {
       // don't care.
     };
  -  fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData);
  -  fs.entityForUri(main).writeAsStringSync("main() {}");
   
     CompilerContext compilerContext = new CompilerContext(
  -      new ProcessedOptions(options: options, inputs: [main]));
  +      new ProcessedOptions(options: options, inputs: [mainUri]));
     return compilerContext;
   }
   
  -String getFileAsStringContent(File file, bool nnbd) {
  -  Uint8List rawBytes = file.readAsBytesSync();
  +String getFileAsStringContent(Uint8List rawBytes, bool nnbd) {
     List<int> lineStarts = new List<int>();
   
     Token firstToken = parser_suite.scanRawBytes(rawBytes,
  
positive.code:       builder.add(sublist(
            latestCrashData, offset + deleteChars, latestCrashData.length));
        candidate = builder.takeBytes();
        if (!await crashesOnCompile(
            fs, main, candidate, compilerContext, initialComponent)) {
          noLongerCrashingAt = deleteChars;
          break;
        }
  
negative.code:   return sb.toString();
  }
  
  void binarySearchDeleteData(Uri uri, Component initialComponent) async {
    Uint8List latestCrashData = fs.data[uri];
    int offset = 0;
    while (offset < latestCrashData.length) {
      print("Working at offset $offset of ${latestCrashData.length}");
  