Bug 575893 - [performance] improve file search: cache CharSequence

Use up to 2MB temporary memory to improve the pattern match.
During file search a custom CharSequence with a complicated
 charAt() is passed.
(with a blocked buffer, which needs too switch blocks
 if position falls out of block range.)
The charAt() is the hotspot during pattern matching.
By converting the sequence once (linary) into a String the
String.charAt() nicely inlines
(with well known constant time behaviour for String.charAt()).

Change-Id: I123732a6052ee536a0f968432b5c5fc7bdf7e4ad
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/185195
Tested-by: Platform Bot <platform-bot@eclipse.org>
Tested-by: Lars Vogel <Lars.Vogel@vogella.com>
Reviewed-by: Lars Vogel <Lars.Vogel@vogella.com>
diff --git a/org.eclipse.search/search/org/eclipse/search/internal/core/text/TextSearchVisitor.java b/org.eclipse.search/search/org/eclipse/search/internal/core/text/TextSearchVisitor.java
index b02ee9a..01a9296 100644
--- a/org.eclipse.search/search/org/eclipse/search/internal/core/text/TextSearchVisitor.java
+++ b/org.eclipse.search/search/org/eclipse/search/internal/core/text/TextSearchVisitor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -86,6 +86,11 @@
 	private static final int NUMBER_OF_LOGICAL_THREADS= Runtime.getRuntime().availableProcessors();
 	private static final int FILES_PER_JOB= 50;
 	private static final int MAX_JOBS_COUNT= 100;
+	/**
+	 * Just any number such that the most source files will fit in. And not too
+	 * big to avoid out of memory.
+	 **/
+	private static final int MAX_BUFFER_LENGTH = 999_999; // max 2MB.
 
 	public static class ReusableMatchAccess extends TextSearchMatchAccess {
 
@@ -519,6 +524,16 @@
 
 	private List<TextSearchMatchAccess> locateMatches(IFile file, CharSequence searchInput, Matcher matcher, IProgressMonitor monitor) throws CoreException {
 		List<TextSearchMatchAccess> occurences= null;
+		if (searchInput.length() < MAX_BUFFER_LENGTH) {
+			// cache the sequence in a single array
+			String converted = searchInput.toString();
+			if (converted.length() != searchInput.length()) {
+				throw new CoreException(Status.error( //
+						searchInput.getClass().getName() + " does not proper implement CharSequence.toString()", //$NON-NLS-1$
+						new IllegalArgumentException("wrong length"))); //$NON-NLS-1$
+			}
+			searchInput = converted;
+		}
 		matcher.reset(searchInput);
 		int k= 0;
 		while (matcher.find()) {