From 6f63ede02c9356683f4f57de7054800f2051d518 Mon Sep 17 00:00:00 2001 From: Karol Sobczak Date: Fri, 27 Nov 2015 08:45:27 +0100 Subject: [PATCH] Use array instead of linked list as Threads pool in NFA --- java/com/google/re2j/Machine.java | 51 +++++++++++++++++-------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/java/com/google/re2j/Machine.java b/java/com/google/re2j/Machine.java index 99683972..55e2befa 100644 --- a/java/com/google/re2j/Machine.java +++ b/java/com/google/re2j/Machine.java @@ -7,9 +7,7 @@ package com.google.re2j; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import static com.google.re2j.MachineInput.EOF; @@ -19,6 +17,8 @@ // Called by RE2.doExecute. class Machine { + private static final int INITIAL_POOL_SIZE = 10; + // A logical thread in the NFA. private static class Thread { Thread(int n) { @@ -30,9 +30,9 @@ private static class Thread { // A queue is a 'sparse array' holding pending threads of execution. See: // research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html - private static class Queue { + private class Queue { - static class Entry { + class Entry { int pc; Thread thread; } @@ -70,12 +70,11 @@ Entry add(int pc) { } // Frees all threads on the thread queue, returning them to the free pool. - void clear(List freePool) { + void clear() { for(int i = 0; i < size; ++i) { Entry entry = dense[i]; if (entry != null && entry.thread != null) { - // free(entry.thread) - freePool.add(entry.thread); + free(entry.thread); } // (don't release dense[i] to GC; recycle it.) } @@ -109,8 +108,8 @@ void clear(List freePool) { private final Queue q0, q1; // pool of available threads - // Really a stack: - private List pool = new ArrayList(); + private Thread pool[] = new Thread[INITIAL_POOL_SIZE]; + private int poolSize = 0; // Whether a match was found. private boolean matched; @@ -132,8 +131,8 @@ void clear(List freePool) { // init() reinitializes an existing Machine for re-use on a new input. void init(int ncap) { - for (Thread t : pool) { - t.cap = new int[ncap]; + for (int i = 0; i < poolSize; ++i) { + pool[i].cap = new int[ncap]; } this.matchcap = new int[ncap]; } @@ -150,17 +149,26 @@ int[] submatches() { // alloc() allocates a new thread with the given instruction. // It uses the free pool if possible. private Thread alloc(Inst inst) { - int n = pool.size(); - Thread t = n > 0 - ? pool.remove(n - 1) - : new Thread(matchcap.length); + Thread t; + if (poolSize > 0) { + t = pool[--poolSize]; + } else { + t = new Thread(matchcap.length); + } + t.inst = inst; return t; } // free() returns t to the free pool. private void free(Thread t) { - pool.add(t); + if (poolSize >= pool.length) { + Thread[] newPool = new Thread[pool.length * 2]; + System.arraycopy(pool, 0, newPool, 0, pool.length); + pool = newPool; + } + + pool[poolSize++] = t; } // match() runs the machine over the input |in| starting at |pos| with the @@ -227,7 +235,7 @@ boolean match(MachineInput in, int pos, int anchor) { runq = nextq; nextq = tmpq; } - nextq.clear(pool); + nextq.clear(); return matched; } @@ -251,8 +259,7 @@ private void step(Queue runq, Queue nextq, int pos, int nextPos, byte b, continue; } if (longest && matched && t.cap.length > 0 && matchcap[0] < t.cap[0]) { - // free(t) - pool.add(t); + free(t); continue; } Inst i = t.inst; @@ -276,8 +283,7 @@ private void step(Queue runq, Queue nextq, int pos, int nextPos, byte b, for (int k = j + 1; k < runq.size; ++k) { Queue.Entry d = runq.dense[k]; if (d.thread != null) { - // free(d.thread) - pool.add(d.thread); + free(d.thread); } } runq.size = 0; @@ -300,8 +306,7 @@ private void step(Queue runq, Queue nextq, int pos, int nextPos, byte b, t = add(nextq, i.out, nextPos, t.cap, nextCond, t); } if (t != null) { - // free(t) - pool.add(t); + free(t); } } runq.size = 0;