aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2011-06-17 10:33:41 -0700
committerShawn O. Pearce <sop@google.com>2011-06-17 12:40:12 -0700
commitee2b172e401c7ae0a07f50f0b1ede441a218a550 (patch)
tree11c5bff7d8f6801af1a27e2fc584d0801ad10282
parent21c76f4d2861122087c5f695f441bbd012c36f9d (diff)
downloadprolog-cafe-ee2b172e401c7ae0a07f50f0b1ede441a218a550.tar.gz
Create PrologMachineCopy to reduce consult costs
Applications that dynamically consult the same code file multiple times can benefit from performing the consult in an isolated interpreter, then freezing that database using a PrologMachineCopy, and later restore it into a new machine.
-rw-r--r--src/lang/BlockingPrologControl.java8
-rw-r--r--src/lang/BufferingPrologControl.java7
-rw-r--r--src/lang/InternalDatabase.java40
-rw-r--r--src/lang/Prolog.java32
-rw-r--r--src/lang/PrologControl.java13
-rw-r--r--src/lang/PrologMachineCopy.java92
6 files changed, 157 insertions, 35 deletions
diff --git a/src/lang/BlockingPrologControl.java b/src/lang/BlockingPrologControl.java
index e788982..33e9219 100644
--- a/src/lang/BlockingPrologControl.java
+++ b/src/lang/BlockingPrologControl.java
@@ -110,9 +110,11 @@ public class BlockingPrologControl
/** Constructs a new <code>BlockingPrologControl</code>. */
public BlockingPrologControl() {
- thread = null;
- result = false;
- resultReady = false;
+ }
+
+ /** Constructs a new <code>BlockingPrologControl</code>. */
+ public BlockingPrologControl(PrologMachineCopy pmc) {
+ super(pmc);
}
/**
diff --git a/src/lang/BufferingPrologControl.java b/src/lang/BufferingPrologControl.java
index c66ca00..a71a18f 100644
--- a/src/lang/BufferingPrologControl.java
+++ b/src/lang/BufferingPrologControl.java
@@ -16,6 +16,13 @@ public class BufferingPrologControl extends PrologControl {
private boolean resSingle;
private Term[] resTemplate;
+ public BufferingPrologControl() {
+ }
+
+ public BufferingPrologControl(PrologMachineCopy pmc) {
+ super(pmc);
+ }
+
/**
* Initialize one or more packages in the interpreter.
*
diff --git a/src/lang/InternalDatabase.java b/src/lang/InternalDatabase.java
index 0de54be..663383f 100644
--- a/src/lang/InternalDatabase.java
+++ b/src/lang/InternalDatabase.java
@@ -18,7 +18,7 @@ public class InternalDatabase {
/* For GC */
/** A list of reusable entry indices. */
- protected LinkedList<Integer> reusableIndices = new LinkedList<Integer>();
+ protected LinkedList<Integer> reusableIndices;
/** the top index of this <code>InternalDatabase</code>. */
protected int top;
@@ -32,11 +32,27 @@ public class InternalDatabase {
public InternalDatabase(int n) {
maxContents = n;
buffer = new Term[Math.min(maxContents, DEFAULT_SIZE)];
+ reusableIndices = new LinkedList<Integer>();
top = -1;
}
- /** Discards all entries. */
- public void init() { eraseAll(); }
+ InternalDatabase(Prolog engine, InternalDatabase src, boolean deepCopy) {
+ maxContents = src.maxContents;
+ buffer = new Term[src.buffer.length];
+ reusableIndices = new LinkedList<Integer>(src.reusableIndices);
+ top = src.top;
+
+ if (deepCopy) {
+ for (int i = 0; i <= top; i++) {
+ Term s = src.buffer[i];
+ if (s != null) {
+ buffer[i] = s.copy(engine);
+ }
+ }
+ } else if (0 <= top) {
+ System.arraycopy(src.buffer, 0, buffer, 0, top + 1);
+ }
+ }
/** Inserts an entry to this <code>InternalDatabase</code>. */
public int insert(Term t) {
@@ -46,12 +62,11 @@ public class InternalDatabase {
return top;
} else {
int i = reusableIndices.remove();
- // System.out.println("Reuse " + i);
buffer[i] = t;
return i;
}
} catch (ArrayIndexOutOfBoundsException e) {
- if (maxContents == buffer.length)
+ if (maxContents <= buffer.length)
throw new SystemException("internal database capacity reached");
int len = buffer.length;
Term[] new_buffer = new Term[Math.min(len+10000, maxContents)];
@@ -73,28 +88,15 @@ public class InternalDatabase {
public Term erase(int i) {
Term t = buffer[i];
buffer[i] = null;
- // System.out.println("add Reuse index" + i);
reusableIndices.add(i);
return t;
}
- /** Discards all entries. */
- protected void eraseAll() {
- while (! empty()) {
- buffer[top--] = null;
- }
- }
-
/** Tests if this has no entry. */
- public boolean empty() {
+ private boolean empty() {
return top == -1;
}
- /** Returns the value of <code>top</code>.
- * @see #top
- */
- public int top() { return top; }
-
/** Shows the contents of this <code>InternalDatabase</code>. */
public void show() {
if (empty())
diff --git a/src/lang/Prolog.java b/src/lang/Prolog.java
index d744667..12876f1 100644
--- a/src/lang/Prolog.java
+++ b/src/lang/Prolog.java
@@ -11,6 +11,7 @@ import java.io.Writer;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
+import java.util.Map;
/**
* Prolog engine.
*
@@ -19,6 +20,8 @@ import java.util.IdentityHashMap;
* @version 1.2
*/
public final class Prolog {
+ private static final SymbolTerm NONE = SymbolTerm.intern("$none");
+
/** Prolog thread */
public PrologControl control;
/** Argument registers */
@@ -128,14 +131,24 @@ public final class Prolog {
}
protected final EnumSet<Feature> features = EnumSet.allOf(Feature.class);
- /** Constructs new Prolog engine. */
- public Prolog(PrologControl c) {
- control = c;
- cont = null;
- trail = new Trail();
- stack = new ChoicePointStack(trail);
- hashManager = new HashtableOfTerm();
- copyHash = new IdentityHashMap<VariableTerm, VariableTerm>();
+ Prolog(PrologControl c) {
+ control = c;
+ trail = new Trail();
+ stack = new ChoicePointStack(trail);
+ copyHash = new IdentityHashMap<VariableTerm, VariableTerm>();
+ hashManager = new HashtableOfTerm();
+ }
+
+ Prolog(PrologControl c, PrologMachineCopy pmc) {
+ control = c;
+ trail = new Trail();
+ stack = new ChoicePointStack(trail);
+ copyHash = new IdentityHashMap<VariableTerm, VariableTerm>();
+
+ // During restore there is no need to copy terms. clause/2 inside of
+ // builtins.pl copies the predicate when it reads from internalDB.
+ hashManager = PrologMachineCopy.copyShallow(pmc.hashManager);
+ internalDB = new InternalDatabase(this, pmc.internalDB, false);
}
/**
@@ -209,7 +222,6 @@ public final class Prolog {
initOnce();
stack.init();
trail.init();
- // pdl.init();
B0 = stack.top();
CPFTimeStamp = Long.MIN_VALUE;
@@ -229,7 +241,7 @@ public final class Prolog {
doubleQuotes = "codes";
printStackTrace = "off";
- exception = SymbolTerm.intern("$none");
+ exception = NONE;
startRuntime = System.currentTimeMillis();
previousRuntime = 0;
diff --git a/src/lang/PrologControl.java b/src/lang/PrologControl.java
index e0d9312..2ee53da 100644
--- a/src/lang/PrologControl.java
+++ b/src/lang/PrologControl.java
@@ -23,8 +23,12 @@ public abstract class PrologControl {
/** Constructs a new <code>PrologControl</code>. */
public PrologControl() {
- engine = new Prolog(this);
- code = null;
+ engine = new Prolog(this);
+ }
+
+ /** Constructs a new <code>PrologControl</code>. */
+ public PrologControl(PrologMachineCopy pmc) {
+ engine = new Prolog(this, pmc);
}
public boolean isEnabled(Prolog.Feature f) {
@@ -53,7 +57,10 @@ public abstract class PrologControl {
public void setMaxDatabaseSize(int size) {
if (engine.aregs != null)
throw new IllegalStateException("Prolog already initialized");
- engine.internalDB = new InternalDatabase(size);
+ if (engine.internalDB != null)
+ engine.internalDB.maxContents = size;
+ else
+ engine.internalDB = new InternalDatabase(size);
}
public PrologClassLoader getPrologClassLoader() {
diff --git a/src/lang/PrologMachineCopy.java b/src/lang/PrologMachineCopy.java
new file mode 100644
index 0000000..4dc3afe
--- /dev/null
+++ b/src/lang/PrologMachineCopy.java
@@ -0,0 +1,92 @@
+package com.googlecode.prolog_cafe.lang;
+
+import java.util.Map;
+
+/**
+ * Backup of a Prolog interpreter that can later create a new interpreter.
+ * <p>
+ * A new interpreter can be bootstrapped by passing this copy object to a
+ * PrologControl constructor. Machine copies are primarily intended to let
+ * callers reuse the state constructed by running {@code consult(+File)} prior
+ * to perform any module initialization or predicate evaluation.
+ * <p>
+ * Only the PrologClassLoader, internal hash manager and database are copied.
+ * These are sections of an interpreter that relate to what code is available.
+ */
+public class PrologMachineCopy {
+ /**
+ * Save the database of a current PrologControl.
+ *
+ * @param ctl control to copy the database of.
+ * @return the copy.
+ */
+ public static PrologMachineCopy save(PrologControl ctl) {
+ return new PrologMachineCopy(ctl.engine);
+ }
+
+ /**
+ * Save the database of a current Prolog interpreter.
+ *
+ * @param engine interpreter to copy the database of.
+ * @return the copy.
+ */
+ public static PrologMachineCopy save(Prolog engine) {
+ return new PrologMachineCopy(engine);
+ }
+
+ protected final PrologClassLoader pcl;
+ protected final HashtableOfTerm hashManager;
+ protected final InternalDatabase internalDB;
+
+ private PrologMachineCopy(Prolog engine) {
+ pcl = engine.pcl;
+
+ // During backup, copy all terms using a single consistent copyHash.
+ // This isolates the copy from the source interpreter, in case it gets
+ // modified again later.
+ //
+ // During restore terms are not copied.
+ try {
+ engine.copyHash.clear();
+
+ hashManager = copyDeep(engine, engine.hashManager);
+ internalDB = new InternalDatabase(engine, engine.internalDB, true);
+ } finally {
+ engine.copyHash.clear();
+ }
+ }
+
+ private static HashtableOfTerm copyDeep(Prolog engine, HashtableOfTerm src) {
+ HashtableOfTerm hm = new HashtableOfTerm();
+ for (Map.Entry<Term, Term> e : src.entrySet()) {
+ Term val = e.getValue().copy(engine);
+
+ if (val.isJavaObject()) {
+ JavaObjectTerm o = (JavaObjectTerm) val;
+ if (o.obj instanceof HashtableOfTerm) {
+ val = new JavaObjectTerm(copyDeep(engine, (HashtableOfTerm) o.obj));
+ }
+ }
+
+ hm.put(e.getKey().copy(engine), val);
+ }
+ return hm;
+ }
+
+ static HashtableOfTerm copyShallow(HashtableOfTerm src) {
+ HashtableOfTerm hm = new HashtableOfTerm();
+ for (Map.Entry<Term, Term> e : src.entrySet()) {
+ Term val = e.getValue();
+
+ if (val.isJavaObject()) {
+ JavaObjectTerm o = (JavaObjectTerm) val;
+ if (o.obj instanceof HashtableOfTerm) {
+ val = new JavaObjectTerm(copyShallow((HashtableOfTerm) o.obj));
+ }
+ }
+
+ hm.put(e.getKey(), val);
+ }
+ return hm;
+ }
+}