// Main routine for Daikon invariant detector
// For documentation, see file doc/daikon.html in the distribution.
package daikon;
import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import checkers.quals.Interned;
import utilMDE.Assert;
import utilMDE.FileIOException;
import utilMDE.Fmt;
import utilMDE.Stopwatch;
import utilMDE.TextFile;
import utilMDE.UtilMDE;
import daikon.config.Configuration;
import daikon.derive.Derivation;
import daikon.inv.Equality;
import daikon.inv.Invariant;
import daikon.inv.OutputFormat;
import daikon.inv.binary.sequenceScalar.Member;
import daikon.inv.binary.sequenceScalar.MemberFloat;
import daikon.inv.binary.sequenceScalar.SeqFloatEqual;
import daikon.inv.binary.sequenceScalar.SeqFloatGreaterEqual;
import daikon.inv.binary.sequenceScalar.SeqFloatGreaterThan;
import daikon.inv.binary.sequenceScalar.SeqFloatLessEqual;
import daikon.inv.binary.sequenceScalar.SeqFloatLessThan;
import daikon.inv.binary.sequenceScalar.SeqIntEqual;
import daikon.inv.binary.sequenceScalar.SeqIntGreaterEqual;
import daikon.inv.binary.sequenceScalar.SeqIntGreaterThan;
import daikon.inv.binary.sequenceScalar.SeqIntLessEqual;
import daikon.inv.binary.sequenceScalar.SeqIntLessThan;
import daikon.inv.binary.sequenceString.MemberString;
import daikon.inv.binary.twoScalar.FloatEqual;
import daikon.inv.binary.twoScalar.FloatGreaterEqual;
import daikon.inv.binary.twoScalar.FloatGreaterThan;
import daikon.inv.binary.twoScalar.FloatLessEqual;
import daikon.inv.binary.twoScalar.FloatLessThan;
import daikon.inv.binary.twoScalar.FloatNonEqual;
import daikon.inv.binary.twoScalar.IntEqual;
import daikon.inv.binary.twoScalar.IntGreaterEqual;
import daikon.inv.binary.twoScalar.IntGreaterThan;
import daikon.inv.binary.twoScalar.IntLessEqual;
import daikon.inv.binary.twoScalar.IntLessThan;
import daikon.inv.binary.twoScalar.IntNonEqual;
import daikon.inv.binary.twoScalar.LinearBinary;
import daikon.inv.binary.twoScalar.LinearBinaryFloat;
import daikon.inv.binary.twoScalar.NumericFloat;
import daikon.inv.binary.twoScalar.NumericInt;
import daikon.inv.binary.twoSequence.PairwiseFloatEqual;
import daikon.inv.binary.twoSequence.PairwiseFloatGreaterEqual;
import daikon.inv.binary.twoSequence.PairwiseFloatGreaterThan;
import daikon.inv.binary.twoSequence.PairwiseFloatLessEqual;
import daikon.inv.binary.twoSequence.PairwiseFloatLessThan;
import daikon.inv.binary.twoSequence.PairwiseIntEqual;
import daikon.inv.binary.twoSequence.PairwiseIntGreaterEqual;
import daikon.inv.binary.twoSequence.PairwiseIntGreaterThan;
import daikon.inv.binary.twoSequence.PairwiseIntLessEqual;
import daikon.inv.binary.twoSequence.PairwiseIntLessThan;
import daikon.inv.binary.twoSequence.PairwiseLinearBinary;
import daikon.inv.binary.twoSequence.PairwiseLinearBinaryFloat;
import daikon.inv.binary.twoSequence.PairwiseNumericFloat;
import daikon.inv.binary.twoSequence.PairwiseNumericInt;
import daikon.inv.binary.twoSequence.Reverse;
import daikon.inv.binary.twoSequence.ReverseFloat;
import daikon.inv.binary.twoSequence.SeqSeqFloatEqual;
import daikon.inv.binary.twoSequence.SeqSeqFloatGreaterEqual;
import daikon.inv.binary.twoSequence.SeqSeqFloatGreaterThan;
import daikon.inv.binary.twoSequence.SeqSeqFloatLessEqual;
import daikon.inv.binary.twoSequence.SeqSeqFloatLessThan;
import daikon.inv.binary.twoSequence.SeqSeqIntEqual;
import daikon.inv.binary.twoSequence.SeqSeqIntGreaterEqual;
import daikon.inv.binary.twoSequence.SeqSeqIntGreaterThan;
import daikon.inv.binary.twoSequence.SeqSeqIntLessEqual;
import daikon.inv.binary.twoSequence.SeqSeqIntLessThan;
import daikon.inv.binary.twoSequence.SeqSeqStringEqual;
import daikon.inv.binary.twoSequence.SeqSeqStringGreaterEqual;
import daikon.inv.binary.twoSequence.SeqSeqStringGreaterThan;
import daikon.inv.binary.twoSequence.SeqSeqStringLessEqual;
import daikon.inv.binary.twoSequence.SeqSeqStringLessThan;
import daikon.inv.binary.twoSequence.SubSequence;
import daikon.inv.binary.twoSequence.SubSequenceFloat;
import daikon.inv.binary.twoSequence.SubSet;
import daikon.inv.binary.twoSequence.SubSetFloat;
import daikon.inv.binary.twoSequence.SuperSequence;
import daikon.inv.binary.twoSequence.SuperSequenceFloat;
import daikon.inv.binary.twoSequence.SuperSet;
import daikon.inv.binary.twoSequence.SuperSetFloat;
import daikon.inv.binary.twoString.StringEqual;
import daikon.inv.binary.twoString.StringGreaterEqual;
import daikon.inv.binary.twoString.StringGreaterThan;
import daikon.inv.binary.twoString.StringLessEqual;
import daikon.inv.binary.twoString.StringLessThan;
import daikon.inv.binary.twoString.StringNonEqual;
import daikon.inv.ternary.threeScalar.FunctionBinary;
import daikon.inv.ternary.threeScalar.FunctionBinaryFloat;
import daikon.inv.ternary.threeScalar.LinearTernary;
import daikon.inv.ternary.threeScalar.LinearTernaryFloat;
import daikon.inv.unary.scalar.LowerBound;
import daikon.inv.unary.scalar.LowerBoundFloat;
import daikon.inv.unary.scalar.Modulus;
import daikon.inv.unary.scalar.NonModulus;
import daikon.inv.unary.scalar.NonZero;
import daikon.inv.unary.scalar.NonZeroFloat;
import daikon.inv.unary.scalar.OneOfFloat;
import daikon.inv.unary.scalar.OneOfScalar;
import daikon.inv.unary.scalar.RangeFloat;
import daikon.inv.unary.scalar.RangeInt;
import daikon.inv.unary.scalar.UpperBound;
import daikon.inv.unary.scalar.UpperBoundFloat;
import daikon.inv.unary.sequence.CommonFloatSequence;
import daikon.inv.unary.sequence.CommonSequence;
import daikon.inv.unary.sequence.EltLowerBound;
import daikon.inv.unary.sequence.EltLowerBoundFloat;
import daikon.inv.unary.sequence.EltNonZero;
import daikon.inv.unary.sequence.EltNonZeroFloat;
import daikon.inv.unary.sequence.EltOneOf;
import daikon.inv.unary.sequence.EltOneOfFloat;
import daikon.inv.unary.sequence.EltRangeFloat;
import daikon.inv.unary.sequence.EltRangeInt;
import daikon.inv.unary.sequence.EltUpperBound;
import daikon.inv.unary.sequence.EltUpperBoundFloat;
import daikon.inv.unary.sequence.EltwiseFloatEqual;
import daikon.inv.unary.sequence.EltwiseFloatGreaterEqual;
import daikon.inv.unary.sequence.EltwiseFloatGreaterThan;
import daikon.inv.unary.sequence.EltwiseFloatLessEqual;
import daikon.inv.unary.sequence.EltwiseFloatLessThan;
import daikon.inv.unary.sequence.EltwiseIntEqual;
import daikon.inv.unary.sequence.EltwiseIntGreaterEqual;
import daikon.inv.unary.sequence.EltwiseIntGreaterThan;
import daikon.inv.unary.sequence.EltwiseIntLessEqual;
import daikon.inv.unary.sequence.EltwiseIntLessThan;
import daikon.inv.unary.sequence.NoDuplicates;
import daikon.inv.unary.sequence.NoDuplicatesFloat;
import daikon.inv.unary.sequence.OneOfFloatSequence;
import daikon.inv.unary.sequence.OneOfSequence;
import daikon.inv.unary.sequence.SeqIndexFloatEqual;
import daikon.inv.unary.sequence.SeqIndexFloatGreaterEqual;
import daikon.inv.unary.sequence.SeqIndexFloatGreaterThan;
import daikon.inv.unary.sequence.SeqIndexFloatLessEqual;
import daikon.inv.unary.sequence.SeqIndexFloatLessThan;
import daikon.inv.unary.sequence.SeqIndexFloatNonEqual;
import daikon.inv.unary.sequence.SeqIndexIntEqual;
import daikon.inv.unary.sequence.SeqIndexIntGreaterEqual;
import daikon.inv.unary.sequence.SeqIndexIntGreaterThan;
import daikon.inv.unary.sequence.SeqIndexIntLessEqual;
import daikon.inv.unary.sequence.SeqIndexIntLessThan;
import daikon.inv.unary.sequence.SeqIndexIntNonEqual;
import daikon.inv.unary.string.OneOfString;
import daikon.inv.unary.string.PrintableString;
import daikon.inv.unary.stringsequence.CommonStringSequence;
import daikon.inv.unary.stringsequence.EltOneOfString;
import daikon.inv.unary.stringsequence.OneOfStringSequence;
import daikon.split.ContextSplitterFactory;
import daikon.split.SpinfoFileParser;
import daikon.split.Splitter;
import daikon.split.SplitterFactory;
import daikon.split.SplitterList;
import daikon.suppress.NIS;
import daikon.suppress.NIS.SuppressionProcessor;
/**
* The "main" method is the main entry point for the Daikon invariant detector.
* The "mainHelper" method is the entry point, when called programmatically.
**/
public final class Daikon {
private Daikon() {
throw new Error("do not instantiate");
}
/**
* The amount of time to wait between updates of the progress
* display, measured in milliseconds. A value of -1 means not to
* print the progress display at all.
**/
public static int dkconfig_progress_delay = 1000;
/** If true, show stack traces for errors such as file format errors **/
public static boolean dkconfig_show_stack_trace = false;
public static final String release_version = "4.3.1";
public static final String release_date = "August 2, 2007";
public static final String release_string =
"Daikon version "
+ release_version
+ ", released "
+ release_date
+ "; http://pag.csail.mit.edu/daikon.";
// Variables starting with dkconfig_ should only be set via the
// daikon.config.Configuration interface.
/**
* Boolean. Controls whether conditional program points
* are displayed.
**/
public static boolean dkconfig_output_conditionals = true;
// Variables starting with dkconfig_ should only be set via the
// daikon.config.Configuration interface.
/**
* Boolean. Controls whether invariants are reported over floating-point
* values.
**/
public static boolean dkconfig_enable_floats = true;
/**
* Boolean. Just print the total number of possible invariants
* and exit.
*/
public static boolean dkconfig_calc_possible_invs;
/**
* Integer. Percentage of program points to process. All program points
* are sorted by name, and all samples for
* the first <code>ppt_perc</code> program points are processed.
* A percentage of 100 matches all program points.
*/
public static int dkconfig_ppt_perc = 100;
/**
* Boolean. Controls whether or not the total samples read and processed
* are printed at the end of processing.
*/
public static boolean dkconfig_print_sample_totals = false;
// All these variables really need to be organized better.
public static final String lineSep = Global.lineSep;
/**
* Boolean. Controls whether or not splitting based on the built-in
* splitting rules is disabled. The built-in rules look for implications
* based on boolean return values and also when there are exactly two
* exit points from a method.
**/
public static boolean dkconfig_disable_splitting = false;
/**
* Boolean. Controls whether or not processing information is printed out.
* Setting this variable to true also automatically sets
* <code>progress_delay</code> to -1.
**/
public static boolean dkconfig_quiet = false;
// Change this at your peril; high costs in time and space for "false",
// because so many more invariants get instantiated.
public static final boolean check_program_types = true;
// Problem with setting this to true:
// get no invariants over any value that can ever be missing
// Problem with setting this to false:
// due to differrent number of samples, IsEqualityComparison is
// non-transitive (that is specially handled in the code)
public static final boolean invariants_check_canBeMissing = false;
// Specialized version for array elements; only examined if
// invariants_check_canBeMissing is false
public static final boolean invariants_check_canBeMissing_arrayelt = true;
public static final boolean disable_modbit_check_message = false;
// Not a good idea to set this to true, as it is too easy to ignore the
// warnings and the modbit problem can cause an error later.
public static final boolean disable_modbit_check_error = false;
// When true, don't print textual output.
public static boolean no_text_output = false;
// When true, show how much time each program point took.
// Has no effect unless no_text_output is true.
public static boolean show_progress = false;
/**
* Whether to use the "new" equality set mechanism for handling
* equality, using canonicals to have instantiation of invariants
* only over equality sets.
**/
public static boolean use_equality_optimization = true;
/**
* Whether to use the dynamic constants optimization. This
* optimization doesn't instantiate invariants over constant
* variables (i.e., that that have only seen one value). When the
* variable receives a second value, invariants are instantiated and
* are given the sample representing the previous constant value.
**/
public static boolean dkconfig_use_dynamic_constant_optimization = true;
/**
* Boolean. Controls whether the Daikon optimizations (equality
* sets, suppressions) are undone at the end to create a more
* complete set of invariants. Output does not include
* conditional program points, implications, reflexive and
* partially reflexive invariants.
**/
public static boolean dkconfig_undo_opts = false;
/**
* Boolean. Indicates to Daikon classes and methods that the methods
* calls should be compatible to DaikonSimple because Daikon and DaikonSimple share
* methods. Default value is 'false'.
**/
public static boolean using_DaikonSimple = false;
/**
* If "always", then invariants are always guarded.
* If "never", then invariants are never guarded.
* If "missing", then invariants are guarded only for variables that
* were missing (``can be missing'') in the dtrace (the observed executions).
* <p>
* Guarding means that predicates are attached to invariants ensuring
* their values can be dereferenced. For instance, if <code>a.b</code>
* can be missing, and
* <samp>a.b == 5</samp>
* is an invariant, then it is more properly written as
* <samp>(a != null) ==> (a.b == 5)</samp>.
**/
// Perhaps a better default would be "missing".
public static /*@Interned*/ String dkconfig_guardNulls = "default";
/**
* When true compilation errors during splitter file generation
* will not be reported to the user.
*/
public static boolean dkconfig_suppressSplitterErrors = false;
/**
* Whether to associate the program points in a dataflow hierarchy,
* as via Nimmer's thesis. Deactivate only for languages and
* analyses where flow relation is nonsensical.
**/
public static boolean use_dataflow_hierarchy = true;
/**
* Whether to use the bottom up implementation of the dataflow
* hierarchy. This mechanism builds invariants initially
* only at the leaves of the partial order. Upper points are
* calculated by joining the invariants from each of their children
* points.
**/
// public static boolean dkconfig_df_bottom_up = true;
// When true, don't print invariants when their controlling ppt
// already has them. For example, this is the case for invariants
// in public methods which are already given as part of the object
// invariant for that class.
public static boolean suppress_implied_controlled_invariants = true;
// When true, don't print EXIT invariants over strictly orig()
// variables when the corresponding entry ppt already has the
// invariant.
public static boolean suppress_implied_postcondition_over_prestate_invariants =
false;
// When true, use the Simplify theorem prover (not part of Daikon)
// to locate logically redundant invariants, and flag them as
// redundant, so that they are removed from the printed output.
public static boolean suppress_redundant_invariants_with_simplify = false;
// Set what output style to use. DAIKON is the default; ESC style
// is based on JML; SIMPLIFY style uses first order logical
// expressions with lots of parens
public static OutputFormat output_format = OutputFormat.DAIKON;
// public static OutputFormat output_format = OutputFormat.ESCJAVA;
// public static OutputFormat output_format = OutputFormat.DBCJAVA;
// public static OutputFormat output_format = OutputFormat.SIMPLIFY;
// When true, output numbers of values and samples (also names of variables)
public static boolean output_num_samples = false;
public static boolean ignore_comparability = false;
// Controls which program points/variables are used/ignored.
public static Pattern ppt_regexp;
public static Pattern ppt_omit_regexp;
public static Pattern var_regexp;
public static Pattern var_omit_regexp;
/**
* When true, perform detailed internal checking.
* These are essentially additional, possibly costly assert statements.
*/
public static boolean dkconfig_internal_check = false;
/**
* If set, only ppts less than ppt_max_name are included. Used by the
* configuration option dkconfig_ppt_percent to only work on a specified
* percent of the ppts.
*/
public static String ppt_max_name = null;
// The invariants detected will be serialized and written to this
// file.
public static File inv_file;
// Whether we want the memory monitor activated
private static boolean use_mem_monitor = false;
/**
* Whether Daikon should print its version number and date.
**/
public static boolean noversion_output = false;
/**
* Whether Daikon is in its inferencing loop. Used only for
* assertion checks.
**/
public static boolean isInferencing = false;
/**
* When true, omit certain invariants from the output .inv
* file. Generally these are invariants that wouldn't be printed in
* any case; but by default, they're retained in the .inv file in
* case they would be useful for later processing. (For instance, we
* might at some point in the future support resuming processing
* with more data from an .inv file). These invariants can increase
* the size of the .inv file, though, so when only limited further
* processing is needed, it can save space to omit them.
**/
public static boolean omit_from_output = false;
/**
* An array of flags, indexed by characters, in which a true entry
* means that invariants of that sort should be omitted from the
* output .inv file.
**/
public static boolean[] omit_types = new boolean[256];
// These variables are public so other programs can reuse the same
// command-line options.
// Please use these switches in the same order in all places where they
// appear (in the code and in the documentation); it makes the code
// easier to read and the documentation easier to keep up to date.
// Control output
public static final String help_SWITCH = "help";
// "-o" switch: file to which serialized output is written
public static final String no_text_output_SWITCH = "no_text_output";
public static final String format_SWITCH = "format";
public static final String show_progress_SWITCH = "show_progress";
public static final String no_show_progress_SWITCH = "no_show_progress";
public static final String noversion_SWITCH = "noversion";
public static final String output_num_samples_SWITCH = "output_num_samples";
public static final String files_from_SWITCH = "files_from";
public static final String omit_from_output_SWITCH = "omit_from_output";
// Control invariant detection
public static final String conf_limit_SWITCH = "conf_limit";
public static final String list_type_SWITCH = "list_type";
public static final String no_dataflow_hierarchy_SWITCH = "nohierarchy";
public static final String suppress_redundant_SWITCH = "suppress_redundant";
// Process only part of the trace file
public static final String ppt_regexp_SWITCH = "ppt-select-pattern";
public static final String ppt_omit_regexp_SWITCH = "ppt-omit-pattern";
public static final String var_regexp_SWITCH = "var-select-pattern";
public static final String var_omit_regexp_SWITCH = "var-omit-pattern";
// Configuration options
public static final String server_SWITCH = "server"; //YOAV: server mode for Daikon: reads dtrace files as they appear
public static final String config_SWITCH = "config";
public static final String config_option_SWITCH = "config_option";
// Debugging
public static final String debugAll_SWITCH = "debug";
public static final String debug_SWITCH = "dbg";
public static final String track_SWITCH = "track";
public static final String disc_reason_SWITCH = "disc_reason";
public static final String mem_stat_SWITCH = "mem_stat";
public static File server_dir = null; //YOAV: the directory from which we read the dtrace files
// A pptMap which contains all the Program Points
public static PptMap all_ppts;
/** current invariant (used for debugging) **/
public static Invariant current_inv = null;
/* List of prototype invariants (one for each type of invariant) */
public static ArrayList<Invariant> proto_invs = new ArrayList<Invariant>();
/** Debug tracer. **/
public static final Logger debugTrace = Logger.getLogger("daikon.Daikon");
public static final Logger debugProgress =
Logger.getLogger("daikon.Progress");
public static final Logger debugEquality =
Logger.getLogger("daikon.Equality");
/** Debug tracer for ppt initialization. **/
public static final Logger debugInit = Logger.getLogger("daikon.init");
/** Prints out statistics concerning equality sets, suppressions, etc. **/
public static final Logger debugStats = Logger.getLogger("daikon.stats");
// Avoid problems if daikon.Runtime is loaded at analysis (rather than
// test-run) time. This might have to change when JTrace is used.
static {
daikon.Runtime.no_dtrace = true;
}
private static Stopwatch stopwatch = new Stopwatch();
static String usage =
UtilMDE.joinLines(
release_string,
"Daikon invariant detector, copyright 1998-2007",
// " by Michael Ernst <mernst@csail.mit.edu>",
"Uses the Java port of GNU getopt, copyright (c) 1998 Aaron M. Renn",
// "For licensing information, see the License section of the manual.",
"Usage:",
" java daikon.Daikon [flags...] files...",
" Each file is a declaration file or a data trace file; the file type",
" is determined by the file name (containing \".decls\" or \".dtrace\").",
" For a list of flags, see the Daikon manual, which appears in the ",
" Daikon distribution and also at http://pag.csail.mit.edu/daikon/.",
" --"+server_SWITCH+" dir",
" Server mode for Daikon in which it reads files from <dir> as they appear (sorted lexicographically) until it finds a file ending in '.end'"
);
/**
* Thrown to indicate that main should not print a stack trace, but only
* print the message itself to the user.
* Code in Daikon should throw this Exception in cases of user error, an
* throw other exceptions in cases of a Daikon bug or a system problem
* (like unpredictable IOExceptions).
* If the string is null, then this is normal termination, not an error;
* no message is printed.
**/
public static class TerminationMessage extends RuntimeException {
static final long serialVersionUID = 20050923L;
public TerminationMessage(String s) { super(s); }
public TerminationMessage(String format, Object... args) {
super (String.format (format, args));
}
public TerminationMessage(Exception e) { super(e.getMessage()); }
//public TerminationMessage(String s, LineNumberReader reader, String fileName) {
// super(new FileIOException(s, reader, fileName).getMessage()); }
public TerminationMessage(Object... s) { super(UtilMDE.joinLines(s)); }
public TerminationMessage() { super(); }
}
/**
* The arguments to daikon.Daikon are file names. Declaration file names
* end in ".decls", and data trace file names end in ".dtrace".
**/
public static void main(final String[] args) {
try {
mainHelper(args);
} catch (Configuration.ConfigException e) {
// I don't think this can happen. -MDE
System.err.println(e.getMessage());
System.exit(1);
} catch (TerminationMessage e) {
if (e.getMessage() != null) {
System.err.println(e.getMessage());
if (dkconfig_show_stack_trace)
e.printStackTrace();
System.exit(1);
} else {
System.exit(0);
}
}
// Any exception other than TerminationMessage gets propagated.
// This simplifies debugging by showing the stack trace.
// (TerminationMessages should be clear enough not to need a stack trace.)
}
/**
* This does the work of main, but it never calls System.exit, so it
* is appropriate to be called progrmmatically.
* Termination of the program with a message to the user is indicated by
* throwing TerminationMessage.
* @see #main(String[])
* @see TerminationMessage
**/
public static void mainHelper(final String[] args) {
// Cleanup from any previous runs
cleanup();
// Read command line options
FileOptions files = read_options(args, usage);
Set<File> decls_files = files.decls;
Set<String> dtrace_files = files.dtrace;
Set<File> spinfo_files = files.spinfo;
Set<File> map_files = files.map;
if (server_dir==null && (decls_files.size() == 0) && (dtrace_files.size() == 0)) {
System.out.println("No .decls or .dtrace files specified");
throw new Daikon.TerminationMessage("No .decls or .dtrace files specified");
}
if (Daikon.dkconfig_undo_opts) {
Daikon.dkconfig_disable_splitting = true;
}
if (Daikon.dkconfig_quiet)
Daikon.dkconfig_progress_delay= -1;
// Set up debug traces; note this comes after reading command line options.
LogHelper.setupLogs(Global.debugAll ? LogHelper.FINE : LogHelper.INFO);
if (!noversion_output) {
if (!Daikon.dkconfig_quiet)
System.out.println(release_string);
}
// figure out which algorithm to use in NIS to process suppressions
if (NIS.dkconfig_suppression_processor == SuppressionProcessor.HYBRID) {
NIS.hybrid_method = true;
} else {
if (NIS.dkconfig_suppression_processor == SuppressionProcessor.ANTECEDENT) {
NIS.antecedent_method = true;
NIS.hybrid_method = false;
} else {
assert (NIS.dkconfig_suppression_processor == SuppressionProcessor.FALSIFIED);
NIS.antecedent_method = false;
NIS.hybrid_method = false;
}
}
// Create the list of all invariant types
setup_proto_invs();
if (PrintInvariants.print_discarded_invariants) {
DiscReasonMap.initialize();
}
fileio_progress = new FileIOProgress();
fileio_progress.start();
// Load declarations and splitters
load_spinfo_files(spinfo_files);
all_ppts = load_decls_files(decls_files);
load_map_files(all_ppts, map_files);
all_ppts.trimToSize();
// If requested, just calculate the total number of invariants possible
if (dkconfig_calc_possible_invs) {
fileio_progress.shouldStop = true;
int total_invs = 0;
// Can't use new for syntax because the default iterator for all_ppts
// is not the one I want here.
for (Iterator<PptTopLevel> itor = all_ppts.ppt_all_iterator();
itor.hasNext();
) {
PptTopLevel ppt = itor.next();
System.out.printf("Processing %s with %d variables",
ppt.name(), ppt.var_infos.length);
int inv_cnt = 0;
if (ppt.var_infos.length > 1600) {
System.out.println("Skipping, too many variables!");
} else {
ppt.instantiate_views_and_invariants();
inv_cnt = ppt.invariant_cnt();
ppt.clean_for_merge();
System.out.println(
inv_cnt + " invariants in " + ppt.name());
total_invs += inv_cnt;
}
}
System.out.println(total_invs + "invariants total");
return;
}
// Only for assertion checks
isInferencing = true;
// Infer invariants
process_data(all_ppts, dtrace_files);
isInferencing = false;
if (Debug.logOn())
Debug.check(all_ppts, "After process data");
if (suppress_redundant_invariants_with_simplify) {
suppressWithSimplify(all_ppts);
}
// Check that PptMap created was correct
all_ppts.repCheck();
// Remove undesired invariants, if requested
if (omit_from_output) {
processOmissions(all_ppts);
}
// Write serialized output - must be done before guarding invariants
if (inv_file != null) {
try {
FileIO.write_serialized_pptmap(all_ppts, inv_file);
} catch (IOException e) {
throw new RuntimeException(
"Error while writing .inv file "
+ "'"
+ inv_file
+ "': "
+ e.toString());
}
}
// if ((Daikon.dkconfig_guardNulls == "always") // interned
// || (Daikon.dkconfig_guardNulls == "missing")) { // interned
// // This side-effects the PptMap, but it has already been saved
// // to disk and is now being used only for printing.
// guardInvariants(all_ppts);
// }
// Debug print information about the variables
if (false) {
for (PptTopLevel ppt : all_ppts.all_ppts()) {
System.out.printf ("Dumping variables for ppt %s%n", ppt.name());
for (VarInfo vi : ppt.var_infos) {
System.out.printf (" vi %s%n", vi);
System.out.printf (" file_rep_type = %s%n", vi.file_rep_type);
System.out.printf (" type = %s%n", vi.type);
}
}
}
// print out the invariants for each program point
if (Daikon.dkconfig_undo_opts) {
// Print out the invariants for each program point (sort first)
for (Iterator<PptTopLevel> t = all_ppts.pptIterator(); t.hasNext();) {
PptTopLevel ppt = t.next();
// We do not need to print out program points that have not seen
// any samples.
if (ppt.num_samples() == 0) {
continue;
}
List<Invariant> invs = PrintInvariants.sort_invariant_list(ppt.invariants_vector());
List<Invariant> filtered_invs = filter_invs(invs);
// Sometimes the program points actually differ in number of
// samples seen due to differences in how Daikon and DaikonSimple
// see the variable hierarchy.
System.out.println(
"====================================================");
System.out.println(ppt.name());
System.out.println(ppt.num_samples());
for (Invariant inv : filtered_invs) {
System.out.println(inv.getClass());
System.out.println(inv);
}
}
// exit the program
return;
}
// Display invariants
if (output_num_samples) {
System.out.println(
"The --output_num_samples debugging flag is on.");
System.out.println(
"Some of the debugging output may only make sense to Daikon programmers.");
}
// If they want to see discarded invariants, they probably don't
// want to see the true ones.
if (!PrintInvariants.print_discarded_invariants) {
PrintInvariants.print_invariants(all_ppts);
} else {
PrintInvariants.print_reasons(all_ppts);
}
if (output_num_samples) {
Global.output_statistics();
}
if (dkconfig_print_sample_totals)
System.out.println(FileIO.samples_processed + " samples processed");
// print statistics concerning what invariants are printed
if (debugStats.isLoggable(Level.FINE)) {
for (Iterator<PptTopLevel> itor = all_ppts.ppt_all_iterator();
itor.hasNext();
) {
PptTopLevel ppt = itor.next();
PrintInvariants.print_filter_stats(debugStats, ppt, all_ppts);
}
}
// Done
if (!Daikon.dkconfig_quiet) {
System.out.println("Exiting Daikon.");
}
}
/**
* Cleans up static variables so that mainHelper can be called more
* than once.
*/
public static void cleanup() {
// Stop the thread that prints out progress information
if ((fileio_progress != null)
&& (fileio_progress.getState() != Thread.State.NEW)) {
fileio_progress.shouldStop = true;
try {
fileio_progress.join (2000);
} catch (InterruptedException e) {
}
if (fileio_progress.getState() != Thread.State.TERMINATED) {
throw new TerminationMessage ("Can't stop fileio_progress thead");
}
}
fileio_progress = null;
progress = "";
proto_invs.clear();
}
// Structure for return value of read_options.
// Return an array of {decls, dtrace, spinfo, map} files.
public static class FileOptions {
public Set<File> decls;
public Set<String> dtrace;
public Set<File> spinfo;
public Set<File> map;
public FileOptions(Set<File> decls, Set<String> dtrace, Set<File> spinfo, Set<File> map) {
this.decls = decls;
this.dtrace = dtrace;
this.spinfo = spinfo;
this.map = map;
}
}
///////////////////////////////////////////////////////////////////////////
// Read in the command line options
// Return {decls, dtrace, spinfo, map} files.
protected static FileOptions read_options(String[] args, String usage) {
if (args.length == 0) {
System.out.println(
"Daikon error: no files supplied on command line.");
System.out.println(usage);
throw new Daikon.TerminationMessage();
}
// LinkedHashSet because it can be confusing to users if files (of the
// same type) are gratuitously processed in a different order than they
// were supplied on the command line.
HashSet<File> decl_files = new LinkedHashSet<File>();
HashSet<String> dtrace_files = new LinkedHashSet<String>(); /* either file names or "-"*/
HashSet<File> spinfo_files = new LinkedHashSet<File>();
HashSet<File> map_files = new LinkedHashSet<File>();
LongOpt[] longopts =
new LongOpt[] {
// Control output
new LongOpt(help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(no_text_output_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(show_progress_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(no_show_progress_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(noversion_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(output_num_samples_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(files_from_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(omit_from_output_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
// Control invariant detection
new LongOpt(conf_limit_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(list_type_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(no_dataflow_hierarchy_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(suppress_redundant_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
// Process only part of the trace file
new LongOpt(ppt_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(ppt_omit_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(var_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(var_omit_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
// Configuration options
new LongOpt(server_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(config_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
// Debugging
new LongOpt(debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(disc_reason_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(mem_stat_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
};
Getopt g = new Getopt("daikon.Daikon", args, "ho:", longopts);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0 :
// got a long option
String option_name = longopts[g.getLongind()].getName();
// Control output
if (help_SWITCH.equals(option_name)) {
System.out.println(usage);
throw new Daikon.TerminationMessage();
} else if (no_text_output_SWITCH.equals(option_name)) {
no_text_output = true;
} else if (format_SWITCH.equals(option_name)) {
String format_name = g.getOptarg();
Daikon.output_format = OutputFormat.get(format_name);
if (Daikon.output_format == null) {
throw new Daikon.TerminationMessage(
"Unknown output format: --format " + format_name);
}
} else if (show_progress_SWITCH.equals(option_name)) {
show_progress = true;
LogHelper.setLevel("daikon.Progress", LogHelper.FINE);
} else if (no_show_progress_SWITCH.equals(option_name)) {
show_progress = false;
} else if (noversion_SWITCH.equals(option_name)) {
noversion_output = true;
} else if (output_num_samples_SWITCH.equals(option_name)) {
output_num_samples = true;
} else if (files_from_SWITCH.equals(option_name)) {
String files_from_filename = g.getOptarg();
try {
for (String filename : new TextFile(files_from_filename)) {
// Ignore blank lines in file.
if (filename.equals("")) {
continue;
}
// This code is duplicated below outside the options loop.
// These aren't "endsWith()" because there might be a suffix
// on the end (eg, a date, or ".gz").
File file = new File(filename);
if (!file.exists()) {
throw new Daikon.TerminationMessage(
"File " + filename + " not found.");
}
if (filename.indexOf(".decls") != -1) {
decl_files.add(file);
} else if (filename.indexOf(".dtrace") != -1) {
dtrace_files.add(filename);
} else if (filename.indexOf(".spinfo") != -1) {
spinfo_files.add(file);
} else if (filename.indexOf(".map") != -1) {
map_files.add(file);
} else {
throw new Daikon.TerminationMessage(
"Unrecognized file extension: "
+ filename);
}
}
} catch (IOException e) {
throw new RuntimeException(String.format("Error reading --files_from file: %s", files_from_filename));
}
break;
} else if (omit_from_output_SWITCH.equals(option_name)) {
String f = g.getOptarg();
for (int i = 0; i < f.length(); i++) {
if ("0rs".indexOf(f.charAt(i)) == -1)
throw new Daikon.TerminationMessage(
"omit_from_output flag letter '"
+ f.charAt(i)
+ "' is unknown");
omit_types[f.charAt(i)] = true;
}
omit_from_output = true;
}
// Control invariant detection
else if (conf_limit_SWITCH.equals(option_name)) {
double limit = Double.parseDouble(g.getOptarg());
if ((limit < 0.0) || (limit > 1.0)) {
throw new Daikon.TerminationMessage(
conf_limit_SWITCH + " must be between [0..1]");
}
Configuration.getInstance().apply(
"daikon.inv.Invariant.confidence_limit",
String.valueOf(limit));
} else if (list_type_SWITCH.equals(option_name)) {
try {
String list_type_string = g.getOptarg();
ProglangType.list_implementors.add(
list_type_string);
} catch (Exception e) {
throw new Daikon.TerminationMessage("Problem parsing " + list_type_SWITCH + " option: " + e);
}
break;
} else if (
no_dataflow_hierarchy_SWITCH.equals(option_name)) {
use_dataflow_hierarchy = false;
} else if (suppress_redundant_SWITCH.equals(option_name)) {
suppress_redundant_invariants_with_simplify = true;
}
// Process only part of the trace file
else if (ppt_regexp_SWITCH.equals(option_name)) {
if (ppt_regexp != null)
throw new Daikon.TerminationMessage(
"multiple --"
+ ppt_regexp_SWITCH
+ " regular expressions supplied on command line");
String regexp_string = g.getOptarg();
try {
// System.out.println("Regexp = " + regexp_string);
ppt_regexp =
Pattern.compile(regexp_string);
} catch (Exception e) {
throw new Daikon.TerminationMessage("Bad regexp " + regexp_string + " for " + ppt_regexp_SWITCH + ": " + e.getMessage());
}
break;
} else if (ppt_omit_regexp_SWITCH.equals(option_name)) {
if (ppt_omit_regexp != null)
throw new Daikon.TerminationMessage(
"multiple --"
+ ppt_omit_regexp_SWITCH
+ " regular expressions supplied on command line");
String regexp_string = g.getOptarg();
try {
// System.out.println("Regexp = " + regexp_string);
ppt_omit_regexp =
Pattern.compile(regexp_string);
} catch (Exception e) {
throw new Daikon.TerminationMessage("Bad regexp " + regexp_string + " for " + ppt_omit_regexp_SWITCH + ": " + e.getMessage());
}
break;
} else if (var_regexp_SWITCH.equals(option_name)) {
if (var_regexp != null)
throw new Daikon.TerminationMessage(
"multiple --"
+ var_regexp_SWITCH
+ " regular expressions supplied on command line");
String regexp_string = g.getOptarg();
try {
// System.out.println("Regexp = " + regexp_string);
var_regexp =
Pattern.compile(regexp_string);
} catch (Exception e) {
throw new Daikon.TerminationMessage("Bad regexp " + regexp_string + " for " + var_regexp_SWITCH + ": " + e.getMessage());
}
break;
} else if (var_omit_regexp_SWITCH.equals(option_name)) {
if (var_omit_regexp != null)
throw new Daikon.TerminationMessage(
"multiple --"
+ var_omit_regexp_SWITCH
+ " regular expressions supplied on command line");
String regexp_string = g.getOptarg();
try {
// System.out.println("Regexp = " + regexp_string);
var_omit_regexp =
Pattern.compile(regexp_string);
} catch (Exception e) {
throw new Daikon.TerminationMessage("Bad regexp " + regexp_string + " for " + var_omit_regexp_SWITCH + ": " + e.getMessage());
}
break;
}
else if (server_SWITCH.equals(option_name)) {
String input_dir = g.getOptarg();
server_dir = new File(input_dir);
if (!server_dir.isDirectory() || !server_dir.canRead() || !server_dir.canWrite())
throw new RuntimeException(
"Could not open config file in server directory " + server_dir);
break;
// Configuration options
} else if (config_SWITCH.equals(option_name)) {
String config_file = g.getOptarg();
try {
InputStream stream =
new FileInputStream(config_file);
Configuration.getInstance().apply(stream);
} catch (IOException e) {
throw new Daikon.TerminationMessage(
// Is this the only possible reason for an IOException?
"Could not open config file " + config_file);
}
break;
} else if (config_option_SWITCH.equals(option_name)) {
String item = g.getOptarg();
try {
Configuration.getInstance().apply(item);
} catch (daikon.config.Configuration.ConfigException e) {
throw new Daikon.TerminationMessage(e);
}
break;
}
else if (debugAll_SWITCH.equals(option_name)) {
Global.debugAll = true;
} else if (debug_SWITCH.equals(option_name)) {
LogHelper.setLevel(g.getOptarg(), LogHelper.FINE);
} else if (track_SWITCH.equals(option_name)) {
LogHelper.setLevel("daikon.Debug", LogHelper.FINE);
String error = Debug.add_track(g.getOptarg());
if (error != null) {
throw new Daikon.TerminationMessage(
"Error parsing track argument '"
+ g.getOptarg()
+ "' - "
+ error);
}
} else if (disc_reason_SWITCH.equals(option_name)) {
try {
PrintInvariants.discReasonSetup(g.getOptarg());
} catch (IllegalArgumentException e) {
throw new Daikon.TerminationMessage(e);
}
} else if (mem_stat_SWITCH.equals(option_name)) {
use_mem_monitor = true;
} else {
throw new Daikon.TerminationMessage(
"Unknown option " + option_name + " on command line");
}
break;
case 'h' :
System.out.println(usage);
throw new Daikon.TerminationMessage();
case 'o' :
String inv_filename = g.getOptarg();
if (inv_file != null) {
throw new Daikon.TerminationMessage("multiple serialization output files supplied on command line: " + inv_file + " " + inv_filename);
}
inv_file = new File(inv_filename);
if (!UtilMDE.canCreateAndWrite(inv_file)) {
throw new Daikon.TerminationMessage("Cannot write to serialization output file " + inv_file);
}
break;
//
case '?' :
// break; // getopt() already printed an error
System.out.println(usage);
throw new Daikon.TerminationMessage();
//
default :
System.out.println("getopt() returned " + c);
break;
}
}
// This code is duplicated above within the switch processing.
// First check that all the file names are OK, so we don't do lots of
// processing only to bail out at the end.
for (int i = g.getOptind(); i < args.length; i++) {
String filename = args[i];
File file = null;
if (!filename.equals("-") && !filename.equals("+")) {
file = new File(filename);
if (!file.exists()) {
throw new Daikon.TerminationMessage("File " + file + " not found.");
}
filename = file.toString();
}
// These aren't "endsWith()" because there might be a suffix on the end
// (eg, a date or ".gz").
if (filename.indexOf(".decls") != -1) {
decl_files.add(file);
} else if (filename.indexOf(".dtrace") != -1) {
dtrace_files.add(filename);
// Always output an invariant file by default, even if none is
// specified on the command line.
if (inv_file == null) {
String basename;
// This puts the .inv file in the current directory.
basename = new File(filename).getName();
// This puts the .inv file in the same directory as the .dtrace file.
// basename = filename;
int base_end = basename.indexOf(".dtrace");
String inv_filename = basename.substring(0, base_end) + ".inv.gz";
inv_file = new File(inv_filename);
if (!UtilMDE.canCreateAndWrite(inv_file)) {
throw new Daikon.TerminationMessage("Cannot write to file " + inv_file);
}
}
} else if (filename.indexOf(".spinfo") != -1) {
spinfo_files.add(file);
} else if (filename.indexOf(".map") != -1) {
map_files.add(file);
} else if (filename.equals("-") || filename.equals("+")) {
dtrace_files.add(filename);
} else {
throw new Daikon.TerminationMessage("Unrecognized file type: " + file);
}
}
// Set the fuzzy float comparison ratio. This needs to be done after
// any configuration options (which may set the ratio) are processed.
Global.fuzzy.set_rel_diff(Invariant.dkconfig_fuzzy_ratio);
// Setup ppt_max_name based on the specified percentage of ppts to process
if (dkconfig_ppt_perc != 100) {
ppt_max_name = setup_ppt_perc(decl_files, dkconfig_ppt_perc);
System.out.println("Max ppt name = " + ppt_max_name);
}
// Validate guardNulls option
PrintInvariants.validateGuardNulls();
return new FileOptions(decl_files, dtrace_files, spinfo_files, map_files);
}
/**
* Creates the list of prototype invariants for all Daikon invariants.
* New invariants must be added to this list
*/
public static void setup_proto_invs() {
// Unary scalar invariants
{
// OneOf (OneOf.java.jpp)
proto_invs.add(OneOfScalar.get_proto());
proto_invs.add(OneOfFloat.get_proto());
proto_invs.add(OneOfString.get_proto());
// NonZero (NonZero.java.jpp)
proto_invs.add(NonZero.get_proto());
proto_invs.add(NonZeroFloat.get_proto());
// Lower and Upper bound (Bound.java.jpp)
proto_invs.add(LowerBound.get_proto());
proto_invs.add(LowerBoundFloat.get_proto());
proto_invs.add(UpperBound.get_proto());
proto_invs.add(UpperBoundFloat.get_proto());
// Modulus and NonModulus (Modulus.java and NonModulus.java)
proto_invs.add(Modulus.get_proto());
proto_invs.add(NonModulus.get_proto());
// Range invariant (Range.java.jpp)
proto_invs.addAll(RangeInt.get_proto_all());
proto_invs.addAll(RangeFloat.get_proto_all());
// Printable String
proto_invs.add (PrintableString.get_proto());
// Positive (x > 0) (Postive.java). Positive is a sample invariant
// that is only included as an example.
// proto_invs.add (Postive.get_proto());
}
// Unary sequence invariants
{
// OneOf (OneOf.java.jpp)
proto_invs.add(OneOfSequence.get_proto());
proto_invs.add(OneOfFloatSequence.get_proto());
proto_invs.add(OneOfStringSequence.get_proto());
proto_invs.add(EltOneOf.get_proto());
proto_invs.add(EltOneOfFloat.get_proto());
proto_invs.add(EltOneOfString.get_proto());
// Range invariant (Range.java.jpp)
proto_invs.addAll(EltRangeInt.get_proto_all());
proto_invs.addAll(EltRangeFloat.get_proto_all());
// Sequence Index Comparisons (SeqIndexComparison.java.jpp)
proto_invs.add(SeqIndexIntEqual.get_proto());
proto_invs.add(SeqIndexIntNonEqual.get_proto());
proto_invs.add(SeqIndexIntGreaterEqual.get_proto());
proto_invs.add(SeqIndexIntGreaterThan.get_proto());
proto_invs.add(SeqIndexIntLessEqual.get_proto());
proto_invs.add(SeqIndexIntLessThan.get_proto());
proto_invs.add(SeqIndexFloatEqual.get_proto());
proto_invs.add(SeqIndexFloatNonEqual.get_proto());
proto_invs.add(SeqIndexFloatGreaterEqual.get_proto());
proto_invs.add(SeqIndexFloatGreaterThan.get_proto());
proto_invs.add(SeqIndexFloatLessEqual.get_proto());
proto_invs.add(SeqIndexFloatLessThan.get_proto());
// foreach i compare a[i] to a[i+1] (EltwiseIntComparisons.java.jpp)
proto_invs.add(EltwiseIntEqual.get_proto());
proto_invs.add(EltwiseIntLessEqual.get_proto());
proto_invs.add(EltwiseIntGreaterEqual.get_proto());
proto_invs.add(EltwiseIntLessThan.get_proto());
proto_invs.add(EltwiseIntGreaterThan.get_proto());
proto_invs.add(EltwiseFloatEqual.get_proto());
proto_invs.add(EltwiseFloatLessEqual.get_proto());
proto_invs.add(EltwiseFloatGreaterEqual.get_proto());
proto_invs.add(EltwiseFloatLessThan.get_proto());
proto_invs.add(EltwiseFloatGreaterThan.get_proto());
// EltNonZero (EltNonZero.java.jpp)
proto_invs.add(EltNonZero.get_proto());
proto_invs.add(EltNonZeroFloat.get_proto());
// No Duplicates (NoDuplicates.java.jpp)
proto_invs.add(NoDuplicates.get_proto());
proto_invs.add(NoDuplicatesFloat.get_proto());
// Element bounds (Bound.java.jpp)
proto_invs.add(EltLowerBound.get_proto());
proto_invs.add(EltUpperBound.get_proto());
proto_invs.add(EltLowerBoundFloat.get_proto());
proto_invs.add(EltUpperBoundFloat.get_proto());
// CommonSequence (CommonSequence.java.jpp)
proto_invs.add (CommonSequence.get_proto());
proto_invs.add (CommonFloatSequence.get_proto());
// CommonStringSequence (CommonStringSubsequence.java)
proto_invs.add (CommonStringSequence.get_proto()); }
// Binary scalar-scalar invariants
{
// Int, Float, String comparisons (from IntComparisons.java.jpp)
proto_invs.add(IntEqual.get_proto());
proto_invs.add(IntNonEqual.get_proto());
proto_invs.add(IntLessThan.get_proto());
proto_invs.add(IntGreaterThan.get_proto());
proto_invs.add(IntLessEqual.get_proto());
proto_invs.add(IntGreaterEqual.get_proto());
proto_invs.add(FloatEqual.get_proto());
proto_invs.add(FloatNonEqual.get_proto());
proto_invs.add(FloatLessThan.get_proto());
proto_invs.add(FloatGreaterThan.get_proto());
proto_invs.add(FloatLessEqual.get_proto());
proto_invs.add(FloatGreaterEqual.get_proto());
proto_invs.add(StringEqual.get_proto());
proto_invs.add(StringNonEqual.get_proto());
proto_invs.add(StringLessThan.get_proto());
proto_invs.add(StringGreaterThan.get_proto());
proto_invs.add(StringLessEqual.get_proto());
proto_invs.add(StringGreaterEqual.get_proto());
// LinearBinary over integer/float (from LinearBinary.java.jpp)
proto_invs.add(LinearBinary.get_proto());
proto_invs.add(LinearBinaryFloat.get_proto());
// Numeric invariants (from Numeric.java.jpp)
proto_invs.addAll(NumericInt.get_proto_all());
proto_invs.addAll(NumericFloat.get_proto_all());
}
// Binary sequence-sequence invariants
{
// Numeric invariants (from Numeric.java.jpp)
proto_invs.addAll(PairwiseNumericInt.get_proto_all());
proto_invs.addAll(PairwiseNumericFloat.get_proto_all());
// Lexical sequence comparisons (from SeqComparison.java.jpp)
proto_invs.add(SeqSeqIntEqual.get_proto());
proto_invs.add(SeqSeqIntLessThan.get_proto());
proto_invs.add(SeqSeqIntGreaterThan.get_proto());
proto_invs.add(SeqSeqIntLessEqual.get_proto());
proto_invs.add(SeqSeqIntGreaterEqual.get_proto());
proto_invs.add(SeqSeqFloatEqual.get_proto());
proto_invs.add(SeqSeqFloatLessThan.get_proto());
proto_invs.add(SeqSeqFloatGreaterThan.get_proto());
proto_invs.add(SeqSeqFloatLessEqual.get_proto());
proto_invs.add(SeqSeqFloatGreaterEqual.get_proto());
proto_invs.add(SeqSeqStringEqual.get_proto());
proto_invs.add(SeqSeqStringLessThan.get_proto());
proto_invs.add(SeqSeqStringGreaterThan.get_proto());
proto_invs.add(SeqSeqStringLessEqual.get_proto());
proto_invs.add(SeqSeqStringGreaterEqual.get_proto());
// Pairwise sequence comparisons (from PairwiseIntComparison.java.jpp)
proto_invs.add(PairwiseIntEqual.get_proto());
proto_invs.add(PairwiseIntLessThan.get_proto());
proto_invs.add(PairwiseIntGreaterThan.get_proto());
proto_invs.add(PairwiseIntLessEqual.get_proto());
proto_invs.add(PairwiseIntGreaterEqual.get_proto());
proto_invs.add(PairwiseFloatEqual.get_proto());
proto_invs.add(PairwiseFloatLessThan.get_proto());
proto_invs.add(PairwiseFloatGreaterThan.get_proto());
proto_invs.add(PairwiseFloatLessEqual.get_proto());
proto_invs.add(PairwiseFloatGreaterEqual.get_proto());
// Array Reverse (from Reverse.java.jpp)
proto_invs.add(Reverse.get_proto());
proto_invs.add(ReverseFloat.get_proto());
// Pairwise Linear Binary (from PairwiseLinearBinary.java.jpp)
proto_invs.add(PairwiseLinearBinary.get_proto());
proto_invs.add(PairwiseLinearBinaryFloat.get_proto());
// Subset and Superset (from SubSet.java.jpp)
proto_invs.add(SubSet.get_proto());
proto_invs.add(SuperSet.get_proto());
proto_invs.add(SubSetFloat.get_proto());
proto_invs.add(SuperSetFloat.get_proto());
// Subsequence (from SubSequence.java.jpp)
proto_invs.add(SubSequence.get_proto());
proto_invs.add(SubSequenceFloat.get_proto());
proto_invs.add(SuperSequence.get_proto());
proto_invs.add(SuperSequenceFloat.get_proto());
}
// Binary sequence-scalar invariants
{
// Comparison of scalar to each array element (SeqIntComparison.java.jpp)
proto_invs.add(SeqIntEqual.get_proto());
proto_invs.add(SeqIntLessThan.get_proto());
proto_invs.add(SeqIntGreaterThan.get_proto());
proto_invs.add(SeqIntLessEqual.get_proto());
proto_invs.add(SeqIntGreaterEqual.get_proto());
proto_invs.add(SeqFloatEqual.get_proto());
proto_invs.add(SeqFloatLessThan.get_proto());
proto_invs.add(SeqFloatGreaterThan.get_proto());
proto_invs.add(SeqFloatLessEqual.get_proto());
proto_invs.add(SeqFloatGreaterEqual.get_proto());
// Scalar is an element of the array (Member.java.jpp)
proto_invs.add(Member.get_proto());
proto_invs.add(MemberFloat.get_proto());
proto_invs.add(MemberString.get_proto());
}
// Ternary invariants
{
// FunctionBinary (FunctionBinary.java.jpp)
proto_invs.addAll(FunctionBinary.get_proto_all());
proto_invs.addAll(FunctionBinaryFloat.get_proto_all());
// LinearTernary (LinearTernary.java.jpp)
proto_invs.add(LinearTernary.get_proto());
proto_invs.add(LinearTernaryFloat.get_proto());
}
// Remove any elements that are not enabled
for (Iterator<Invariant> i = proto_invs.iterator(); i.hasNext(); ) {
Invariant inv = i.next();
Assert.assertTrue (inv != null);
if (!inv.enabled())
i.remove();
}
}
/**
* Creates upper program points by merging together the invariants
* from all of the lower points.
*/
public static void createUpperPpts (PptMap all_ppts) {
// Process each ppt that doesn't have a parent
for (Iterator<PptTopLevel> i = all_ppts.pptIterator(); i.hasNext(); ) {
PptTopLevel ppt = i.next();
// System.out.printf ("considering ppt %s parents: %s, children: %s\n",
// ppt.name, ppt.parents, ppt.children);
if (ppt.parents.size() == 0) {
ppt.mergeInvs();
}
}
}
/**
* Create combined exit points, setup splitters, and add orig and
* derived variables,
*/
public static void init_ppt (PptTopLevel ppt, PptMap all_ppts) {
if (!Daikon.using_DaikonSimple) {
// Setup splitters. This must be done before adding derived variables.
// Do not add splitters to ppts that were already created by splitters!
if (! (ppt instanceof PptConditional)) {
setup_splitters(ppt);
}
}
// Create orig and derived variables
progress = "Creating orig variables for: " + ppt.name;
create_orig_vars (ppt, all_ppts);
if (!Derivation.dkconfig_disable_derived_variables) {
progress = "Creating derived variables for: " + ppt.name;
ppt.create_derived_variables();
}
if (!Daikon.using_DaikonSimple) {
// Initialize equality sets on leaf nodes
setupEquality(ppt);
// System.out.printf ("initialized equality %s for ppt %s%n",
// ppt.equality_view, ppt.name());
// Recursively initialize ppts created by splitters
if (ppt.has_splitters()) {
for (Iterator<PptConditional> ii = ppt.cond_iterator(); ii.hasNext();){
PptConditional ppt_cond = ii.next();
init_ppt (ppt_cond, all_ppts);
}
}
}
}
/**
* Create EXIT program points as needed for EXITnn program points.
*/
public static void create_combined_exits(PptMap ppts) {
// We can't add the newly created exit Ppts directly to ppts while we
// are iterating over it, so store them temporarily in this map.
PptMap exit_ppts = new PptMap();
for (Iterator<PptTopLevel> i = ppts.pptIterator(); i.hasNext(); ) {
PptTopLevel ppt = i.next();
// skip unless its an EXITnn
if (!ppt.is_subexit())
continue;
PptTopLevel exitnn_ppt = ppt;
PptName exitnn_name = exitnn_ppt.ppt_name;
PptName exit_name = ppt.ppt_name.makeExit();
PptTopLevel exit_ppt = exit_ppts.get(exit_name);
if (debugInit.isLoggable(Level.FINE))
debugInit.fine ("create_combined_exits: encounted exit "
+ exitnn_ppt.name());
// Create the exit, if necessary
if (exit_ppt == null) {
// this is a hack. it should probably filter out orig and derived
// vars instead of taking the first n.
int len = ppt.num_tracevars + ppt.num_static_constant_vars;
VarInfo[] exit_vars = new VarInfo[len];
for (int j = 0; j < len; j++) {
exit_vars[j] = new VarInfo(ppt.var_infos[j]);
exit_vars[j].varinfo_index = ppt.var_infos[j].varinfo_index;
exit_vars[j].value_index = ppt.var_infos[j].value_index;
exit_vars[j].equalitySet = null;
}
exit_ppt
= new PptTopLevel(exit_name.getName(), PptTopLevel.PptType.EXIT,
ppt.parent_relations, ppt.flags, exit_vars);
// exit_ppt.ppt_name.setVisibility(exitnn_name.getVisibility());
exit_ppts.add(exit_ppt);
if (debugInit.isLoggable(Level.FINE))
debugInit.fine ("create_combined_exits: created exit "
+ exit_name);
init_ppt (exit_ppt, ppts);
}
}
// Now add the newly created Ppts to the global map.
for (Iterator<PptTopLevel> i = exit_ppts.pptIterator(); i.hasNext(); ) {
PptTopLevel ppt = i.next();
ppts.add(ppt);
}
}
// The function filters out the reflexive invs in binary slices,
// reflexive and partially reflexive invs in ternary slices
// and also filters out the invariants that have not seen enough
// samples in ternary slices.
static List<Invariant> filter_invs(List<Invariant> invs) {
List<Invariant> new_list = new ArrayList<Invariant>();
for (Invariant inv : invs) {
VarInfo[] vars = inv.ppt.var_infos;
// This check is the most non-intrusive way to filter out the invs
// Filter out reflexive invariants in the binary invs
if (!((inv.ppt instanceof PptSlice2) && vars[0] == vars[1])) {
// Filter out the reflexive and partially reflexive invs in the
// ternary slices
if (!((inv.ppt instanceof PptSlice3) && (vars[0] == vars[1]
|| vars[1] == vars[2] || vars[0] == vars[2]))) {
if (inv.ppt.num_values() != 0) {
// filters out "warning: too few samples for
// daikon.inv.ternary.threeScalar.LinearTernary invariant"
if (inv.isActive()) {
new_list.add(inv);
}
}
}
}
}
return new_list;
}
/**
* Add orig() variables to the given EXIT/EXITnn point, Does nothing if
* exit_ppt is not an EXIT/EXITnn.
*/
private static void create_orig_vars(PptTopLevel exit_ppt, PptMap ppts) {
if (! exit_ppt.ppt_name.isExitPoint()) {
return;
}
if (debugInit.isLoggable(Level.FINE)) {
debugInit.fine ("Doing create and relate orig vars for: "
+ exit_ppt.name());
}
PptTopLevel entry_ppt = ppts.get(exit_ppt.ppt_name.makeEnter());
Assert.assertTrue(entry_ppt != null, exit_ppt.name());
// Add "orig(...)" (prestate) variables to the program point.
// Don't bother to include the constants. Walk through
// entry_ppt's vars. For each non-constant, put it on the
// new_vis worklist after fixing its comparability information.
exit_ppt.num_orig_vars = entry_ppt.num_tracevars;
VarInfo[] new_vis = new VarInfo[exit_ppt.num_orig_vars];
{
VarInfo[] entry_ppt_vis = entry_ppt.var_infos;
int new_vis_index = 0;
for (int k = 0; k < entry_ppt.num_declvars; k++) {
VarInfo vi = entry_ppt_vis[k];
Assert.assertTrue(!vi.isDerived(), "Derived when making orig(): "
+ vi.name());
if (vi.isStaticConstant())
continue;
VarInfo origvar = VarInfo.origVarInfo(vi);
// Fix comparability
VarInfo postvar = exit_ppt.find_var_by_name (vi.name());
if (postvar == null) {
System.out.printf ("Cant find var %s in exit of ppt %s%n", vi,
exit_ppt.name());
for (VarInfo cvi : entry_ppt.var_infos)
System.out.printf (" entry var = %s%n", cvi);
for (VarInfo cvi : exit_ppt.var_infos)
System.out.printf (" exit var = %s%n", cvi);
assert false;
throw new RuntimeException("this can't happen: postvar is null");
}
origvar.postState = postvar;
origvar.comparability = postvar.comparability.makeAlias();
// Add to new_vis
new_vis[new_vis_index] = origvar;
new_vis_index++;
//System.out.printf ("adding origvar %s to ppt %s%n", origvar.name(),
// exit_ppt.name());
}
Assert.assertTrue(new_vis_index == exit_ppt.num_orig_vars);
}
exit_ppt.addVarInfos(new_vis);
}
///////////////////////////////////////////////////////////////////////////
// Read decls, dtrace, etc. files
private static PptMap load_decls_files(Set<File> decl_files) {
stopwatch.reset();
try {
if (!Daikon.dkconfig_quiet) {
System.out.print("Reading declaration files ");
}
PptMap all_ppts = FileIO.read_declaration_files(decl_files);
if (debugTrace.isLoggable(Level.FINE)) {
debugTrace.fine("Initializing partial order");
}
fileio_progress.clear();
if (!Daikon.dkconfig_quiet && decl_files.size() > 0) {
System.out.print(" (read ");
System.out.print(UtilMDE.nplural(decl_files.size(), "decls file"));
System.out.println(")");
}
return all_ppts;
} catch (IOException e) {
// System.out.println();
// e.printStackTrace();
throw new Daikon.TerminationMessage("Error parsing decl file", e);
} finally {
debugProgress.fine(
"Time spent on read_declaration_files: " + stopwatch.format());
}
}
private static void load_spinfo_files(Set<File> spinfo_files) {
if (dkconfig_disable_splitting || spinfo_files.isEmpty()) {
return;
}
stopwatch.reset();
try {
System.out.print("Reading splitter info files ");
create_splitters(spinfo_files);
System.out.print(" (read ");
System.out.print(UtilMDE.nplural(spinfo_files.size(), "spinfo file"));
System.out.println(")");
} catch (IOException e) {
System.out.println();
e.printStackTrace();
throw new Error(e);
} finally {
debugProgress.fine("Time spent on load_spinfo_files: "
+ stopwatch.format());
}
}
private static void load_map_files(PptMap all_ppts, Set<File> map_files) {
stopwatch.reset();
if (!dkconfig_disable_splitting && map_files.size() > 0) {
System.out.print("Reading map (context) files ");
ContextSplitterFactory.load_mapfiles_into_splitterlist(
map_files,
ContextSplitterFactory.dkconfig_granularity);
System.out.print(" (read ");
System.out.print(
UtilMDE.nplural(map_files.size(), "map (context) file"));
System.out.println(")");
debugProgress.fine(
"Time spent on load_map_files: " + stopwatch.format());
}
}
/**
* Sets up splitting on all ppts. Currently only binary splitters
* over boolean returns or exactly two return statements are enabled
* by default (though other splitters can be defined by the user)
*/
public static void setup_splitters(PptTopLevel ppt) {
if (dkconfig_disable_splitting) {
return;
}
SplitterFactory.load_splitters(ppt, parsedSplitters);
Splitter[] pconds = null;
if (SplitterList.dkconfig_all_splitters) {
pconds = SplitterList.get_all();
} else {
pconds = SplitterList.get(ppt.name());
}
if (pconds != null) {
if (Global.debugSplit.isLoggable(Level.FINE)) {
Global.debugSplit.fine(
"Got "
+ UtilMDE.nplural(pconds.length, "splitter")
+ " for "
+ ppt.name());
}
ppt.addConditions(pconds);
}
}
///////////////////////////////////////////////////////////////////////////
// Infer invariants over the trace data
/** Indicate progress for FileIOProgress. **/
public static String progress = "";
/**
* The number of columns of progress information to display. In many
* Unix shells, this can be set to an appropriate value by
* <samp>--config_option daikon.Daikon.progress_display_width=$COLUMNS</samp>.
**/
public static int dkconfig_progress_display_width = 80;
/** A way to output FileIO progress information easily. */
private static FileIOProgress fileio_progress = null;
public static class FileIOProgress extends Thread {
public FileIOProgress() {
setDaemon(true);
pctFmt = NumberFormat.getPercentInstance();
pctFmt.setMinimumFractionDigits(2);
pctFmt.setMaximumFractionDigits(2);
df = DateFormat.getTimeInstance(/*DateFormat.LONG*/
);
}
/**
* Clients should set this variable instead of calling Thread.stop(),
* which is deprecated. Typically a client calls "display()" before
* setting this.
**/
public boolean shouldStop = false;
private static NumberFormat pctFmt;
private DateFormat df;
public void run() {
if (dkconfig_progress_delay == -1)
return;
while (true) {
if (shouldStop) {
clear();
return;
}
display();
try {
sleep(dkconfig_progress_delay);
} catch (InterruptedException e) {
// hmm
}
}
}
/** Clear the display; good to do before printing to System.out. **/
public void clear() {
if (dkconfig_progress_delay == -1)
return;
// "display("");" is wrong becuase it leaves the timestamp and writes
// spaces across the screen.
String status =
UtilMDE.rpad("", dkconfig_progress_display_width - 1);
System.out.print("\r" + status);
System.out.print("\r"); // return to beginning of line
System.out.flush();
}
/**
* Displays the current status.
* Call this if you don't want to wait until the next automatic display.
**/
public void display() {
if (dkconfig_progress_delay == -1)
return;
display(message());
}
/** Displays the given message. **/
public void display(String message) {
if (dkconfig_progress_delay == -1)
return;
String status =
UtilMDE.rpad(
"[" + df.format(new Date()) + "]: " + message,
dkconfig_progress_display_width - 1);
System.out.print("\r" + status);
System.out.flush();
// System.out.println (status);
if (debugTrace.isLoggable(Level.FINE)) {
debugTrace.fine(
"Free memory: "
+ java.lang.Runtime.getRuntime().freeMemory());
debugTrace.fine(
"Used memory: "
+ (java.lang.Runtime.getRuntime().totalMemory()
- java.lang.Runtime.getRuntime().freeMemory()));
if (FileIO.data_trace_state != null)
debugTrace.fine("Active slices: " +
FileIO.data_trace_state.all_ppts.countSlices());
}
}
private String message() {
if (FileIO.data_trace_state == null) {
if (Daikon.progress == null) {
return "[no status]";
} else {
return Daikon.progress;
}
}
String filename = FileIO.data_trace_state.filename;
LineNumberReader lnr = FileIO.data_trace_state.reader;
String line;
if (lnr == null) {
line = "?";
} else {
long lineNum = lnr.getLineNumber();
line = String.valueOf(lineNum);
if (FileIO.data_trace_state.total_lines > 0) {
double frac =
lineNum / (double) FileIO.data_trace_state.total_lines;
String percent = pctFmt.format(frac);
line = line + ", " + percent;
}
}
return "Reading " + filename + " (line " + line + ") ...";
}
}
/**
* The data-processing routine of the daikon engine. At this
* point, the decls and spinfo files have been loaded, all of the
* program points have been setup, and candidate invariants have
* been instantiated. This routine processes data to falsify the
* candidate invariants.
**/
private static void process_data(PptMap all_ppts, Set<String> dtrace_files) {
MemMonitor monitor = null;
if (use_mem_monitor) {
monitor = new MemMonitor("stat.out");
new Thread((Runnable) monitor).start();
}
stopwatch.reset();
// Preprocessing
setup_NISuppression();
// Processing (actually using dtrace files)
try {
fileio_progress.clear();
if (!Daikon.dkconfig_quiet) {
System.out.println(
"Processing trace data; reading "
+ UtilMDE.nplural(dtrace_files.size(), "dtrace file")
+ ":");
}
FileIO.read_data_trace_files(dtrace_files, all_ppts);
fileio_progress.shouldStop = true;
// Final update, so "100%", not "99.70%", is the last thing printed.
fileio_progress.display();
if (!Daikon.dkconfig_quiet) {
System.out.println();
}
// System.out.print("Creating implications "); // XXX untested code
// for (PptTopLevel ppt : all_ppts) {
// System.out.print('.');
// ppt.addImplications();
// }
// System.out.println();
} catch (IOException e) {
System.out.println();
e.printStackTrace();
throw new Error(e);
} finally {
debugProgress.fine(
"Time spent on read_data_trace_files: " + stopwatch.format());
}
if (monitor != null) {
monitor.stop();
}
if (FileIO.dkconfig_read_samples_only) {
throw new Daikon.TerminationMessage(
Fmt.spf(
"Finished reading %s samples",
"" + FileIO.samples_processed));
}
if (all_ppts.size() == 0) {
String message = "No program point declarations were found.";
if (FileIO.omitted_declarations != 0) {
message += lineSep + " " + FileIO.omitted_declarations + " "
+ ((FileIO.omitted_declarations == 1)
? "declaration was"
: "declarations were")
+ " omitted by regexps (e.g., --ppt-select-pattern).";
}
throw new Daikon.TerminationMessage(message);
}
// System.out.println("samples processed: " + FileIO.samples_processed);
// if {
int unmatched_count = FileIO.call_stack.size() + FileIO.call_hashmap.size();
if ((use_dataflow_hierarchy
&& FileIO.samples_processed == unmatched_count)
|| (FileIO.samples_processed == 0)) {
throw new Daikon.TerminationMessage("No samples found for any of "
+ UtilMDE.nplural(all_ppts.size(),
"program point"));
}
// ppt_stats (all_ppts);
// if (debugStats.isLoggable (Level.FINE)) {
// PptSliceEquality.print_equality_stats (debugStats, all_ppts);
// }
// Print equality set info
// for (Iterator<PptTopLevel> i = all_ppts.pptIterator(); i.hasNext(); ) {
// PptTopLevel ppt = i.next();
// Fmt.pf ("ppt: %s", ppt.name);
// if ((ppt.equality_view == null) || (ppt.equality_view.invs == null))
// continue;
// for (Invariant inv : ppt.equality_view.invs) {
// Equality e = (Equality) inv;
// Fmt.pf (" equality set = %s", e);
// }
// }
// Fmt.pf ("printing ternary invariants");
// PrintInvariants.print_all_ternary_invs (all_ppts);
// System.exit(0);
// Postprocessing
stopwatch.reset();
debugProgress.fine("Create Combined Exits ... ");
create_combined_exits(all_ppts);
// Post process dynamic constants
if (dkconfig_use_dynamic_constant_optimization) {
debugProgress.fine("Constant Post Processing ... ");
for (Iterator<PptTopLevel> itor = all_ppts.ppt_all_iterator();
itor.hasNext();
) {
PptTopLevel ppt = itor.next();
if (ppt.constants != null)
ppt.constants.post_process();
}
}
// Initialize the partial order hierarchy
debugProgress.fine("Init Hierarchy ... ");
if (FileIO.new_decl_format)
PptRelation.init_hierarchy_new (all_ppts);
else
PptRelation.init_hierarchy(all_ppts);
debugProgress.fine("Init Hierarchy ... done");
// Calculate invariants at all non-leaf ppts
if (use_dataflow_hierarchy) {
debugProgress.fine("createUpperPpts");
createUpperPpts(all_ppts);
debugProgress.fine("createUpperPpts ... done");
}
// Equality data for each PptTopLevel.
if (Daikon.use_equality_optimization && !Daikon.dkconfig_undo_opts) {
debugProgress.fine("Equality Post Process ... ");
for (Iterator<PptTopLevel> itor = all_ppts.ppt_all_iterator();
itor.hasNext();
) {
PptTopLevel ppt = itor.next();
ppt.postProcessEquality();
}
debugProgress.fine("Equality Post Process ... done");
}
// undo optimizations; results in a more redundant but more complete
// set of invariants
if (Daikon.dkconfig_undo_opts) {
undoOpts(all_ppts);
}
// Debug print information about equality sets
if (debugEquality.isLoggable(Level.FINE)) {
for (Iterator<PptTopLevel> itor = all_ppts.ppt_all_iterator();
itor.hasNext();
) {
PptTopLevel ppt = itor.next();
debugEquality.fine(ppt.name() + ": " + ppt.equality_sets_txt());
}
}
debugProgress.fine ("Time spent on non-implication postprocessing: "
+ stopwatch.format());
isInferencing = false;
// Add implications
stopwatch.reset();
fileio_progress.clear();
if (! Daikon.dkconfig_disable_splitting) {
// This isn't helpful to users. Perhaps add an option that prints it.
// if (!Daikon.dkconfig_quiet) {
// System.out.println("Creating implications");
// }
debugProgress.fine("Adding Implications ... ");
for (Iterator<PptTopLevel> itor = all_ppts.pptIterator(); itor.hasNext();) {
PptTopLevel ppt = itor.next();
// debugProgress.fine (" Adding Implications for " + ppt.name);
ppt.addImplications();
}
debugProgress.fine("Time spent adding implications: "
+ stopwatch.format());
}
}
private static class Count {
public int val;
Count (int val) {
this.val = val;
}
}
/**
* Print out basic statistics (samples, invariants, variables, etc)
* about each ppt
*/
public static void ppt_stats (PptMap all_ppts) {
int all_ppt_cnt = 0;
int ppt_w_sample_cnt = 0;
for (Iterator<PptTopLevel> i = all_ppts.pptIterator(); i.hasNext(); ) {
PptTopLevel ppt = i.next();
all_ppt_cnt++;
if (ppt.num_samples() == 0)
continue;
ppt_w_sample_cnt++;
Fmt.pf ("%s", ppt.name());
Fmt.pf (" samples = " + ppt.num_samples());
Fmt.pf (" invariants = " + ppt.invariant_cnt());
Map<ProglangType,Count> type_map = new LinkedHashMap<ProglangType,Count>();
int leader_cnt = 0;
for (VarInfo v : ppt.var_infos) {
if (!v.isCanonical())
continue;
leader_cnt++;
Count cnt = type_map.get (v.file_rep_type);
if (cnt == null)
type_map.put (v.file_rep_type, cnt = new Count(0));
cnt.val++;
}
Fmt.pf (" vars = " + ppt.var_infos.length);
Fmt.pf (" leaders = " + leader_cnt);
for (Map.Entry<ProglangType,Count> e : type_map.entrySet()) {
ProglangType file_rep_type = e.getKey();
Count cnt = e.getValue();
Fmt.pf (" %s = %s", file_rep_type, "" + cnt.val);
}
}
Fmt.pf ("Total ppt count = " + all_ppt_cnt);
Fmt.pf ("PPts w/sample count = " + ppt_w_sample_cnt);
}
/**
* Process the invariants with simplify to remove redundant invariants
*/
private static void suppressWithSimplify(PptMap all_ppts) {
System.out.print("Invoking Simplify to identify redundant invariants");
System.out.flush();
stopwatch.reset();
for (Iterator<PptTopLevel> itor = all_ppts.ppt_all_iterator(); itor.hasNext();) {
PptTopLevel ppt = itor.next();
ppt.mark_implied_via_simplify(all_ppts);
System.out.print(".");
System.out.flush();
}
System.out.println(stopwatch.format());
}
/**
* Initialize NIS suppression
*/
public static void setup_NISuppression() {
NIS.init_ni_suppression();
}
/**
* Initialize the equality sets for each variable
*/
public static void setupEquality (PptTopLevel ppt) {
if (!Daikon.use_equality_optimization)
return;
// Skip points that are not leaves.
if (use_dataflow_hierarchy) {
PptTopLevel p = ppt;
if (ppt instanceof PptConditional)
p = ((PptConditional)ppt).parent;
// Rather than defining leaves as :::GLOBAL or :::EXIT54 (numbered
// exit), we define them as everything except
// ::EXIT (combined), :::ENTER, :::THROWS, :::OBJECT
// and :::CLASS program points. This scheme ensures that arbitrarly
// named program points such as :::POINT (used by convertcsv.pl)
// will be treated as leaves.
if (p.ppt_name.isCombinedExitPoint() ||
p.ppt_name.isEnterPoint() ||
p.ppt_name.isThrowsPoint() ||
p.ppt_name.isObjectInstanceSynthetic() ||
p.ppt_name.isClassStaticSynthetic()) {
return;
}
if (ppt.has_splitters())
return;
}
// Create the initial equality sets
ppt.equality_view = new PptSliceEquality(ppt);
ppt.equality_view.instantiate_invariants();
}
/**
* Create user defined splitters
*/
private static List<SpinfoFileParser> parsedSplitters = new ArrayList<SpinfoFileParser>();
public static void create_splitters(Set<File> spinfo_files)
throws IOException {
for (File filename : spinfo_files) {
SpinfoFileParser p = SplitterFactory.parse_spinfofile (filename);
parsedSplitters.add(p);
}
}
// /**
// * Guard the invariants at all PptTopLevels. Note that this changes
// * the contents of the PptTopLevels, and the changes made should
// * probably not be written out to an inv file (save the file before
// * this is called).
// */
// public static void guardInvariants(PptMap allPpts) {
// for (PptTopLevel ppt : allPpts.asCollection()) {
// if (ppt.num_samples() == 0)
// continue;
// // Make sure isDerivedParam is set before guarding. Otherwise
// // we'll never get it correct.
// for (int iVarInfo = 0;
// iVarInfo < ppt.var_infos.length;
// iVarInfo++) {
// boolean temp =
// ppt.var_infos[iVarInfo].isDerivedParamAndUninteresting();
// }
//
// ppt.guardInvariants();
// }
// }
/**
* Removed invariants as specified in omit_types
*/
private static void processOmissions(PptMap allPpts) {
if (omit_types['0'])
allPpts.removeUnsampled();
for (PptTopLevel ppt : allPpts.asCollection()) {
ppt.processOmissions(omit_types);
}
}
/**
* Returns the max ppt that corresponds to the specified percentage
* of ppts (presuming that only those ppts <= max_ppt will be
* processed).
*/
private static String setup_ppt_perc(Collection<File> decl_files, int ppt_perc) {
// Make sure the percentage is valid
if ((ppt_perc < 1) || (ppt_perc > 100))
// The number should already have been checked, so use Error instead of Daikon.TerminationMessage
throw new Error(
"ppt_perc of " + ppt_perc + " is out of range 1..100");
if (ppt_perc == 100)
return null;
// Keep track of all of the ppts in a set ordered by the ppt name
Set<String> ppts = new TreeSet<String>();
// Read all of the ppt names out of the decl files
try {
for (File file : decl_files) {
// Open the file
LineNumberReader fp = UtilMDE.lineNumberFileReader(file);
// Read each ppt name from the file
for (String line = fp.readLine();
line != null;
line = fp.readLine()) {
if (line.equals("") || FileIO.isComment(line))
continue;
if (!line.equals("DECLARE"))
continue;
String ppt_name = fp.readLine();
ppts.add(ppt_name);
}
fp.close();
}
} catch (IOException e) {
e.printStackTrace();
throw new Error(e);
}
// Determine the ppt_name that matches the specified percentage. Always
// return the last exit point from the method (so we don't get half the
// exits from a method or enters without exits, etc)
int ppt_cnt = (ppts.size() * ppt_perc) / 100;
if (ppt_cnt == 0)
throw new Daikon.TerminationMessage(
"ppt_perc of "
+ ppt_perc
+ "% results in processing 0 out of "
+ ppts.size()
+ " ppts");
for (Iterator<String> i = ppts.iterator(); i.hasNext();) {
String ppt_name = i.next();
if (--ppt_cnt <= 0) {
String last_ppt_name = ppt_name;
while (i.hasNext()) {
ppt_name = i.next();
if ((last_ppt_name.indexOf("EXIT") != -1)
&& (ppt_name.indexOf("EXIT") == -1))
return (last_ppt_name);
last_ppt_name = ppt_name;
}
return (ppt_name);
}
}
// Execution should not reach this line
throw new Error("ppt_cnt " + ppt_cnt + " ppts.size " + ppts.size());
}
/**
* Undoes the invariants suppressed for the dynamic constant,
* suppression and equality set optimizations (should yield the same
* invariants as the simple incremental algorithm
*/
public static void undoOpts(PptMap all_ppts) {
//undo suppressions
Iterator<PptTopLevel> suppress_it = all_ppts.ppt_all_iterator();
while (suppress_it.hasNext()) {
PptTopLevel p = suppress_it.next();
NIS.create_suppressed_invs(p);
}
//undo equality sets
Iterator<PptTopLevel> equality_it = all_ppts.ppt_all_iterator();
while (equality_it.hasNext()) {
PptTopLevel ppt = equality_it.next();
PptSliceEquality sliceEquality = ppt.equality_view;
// some program points have no equality sets?
if (sliceEquality == null) {
// System.out.println(ppt.name);
continue;
}
// get the new leaders
List<Equality> allNewInvs = new ArrayList<Equality>();
for (Invariant eq_as_inv : sliceEquality.invs) {
Equality eq = (Equality) eq_as_inv;
VarInfo leader = eq.leader();
List<VarInfo> vars = new ArrayList<VarInfo>();
for (VarInfo var : eq.getVars()) {
if (!var.equals(leader)) {
vars.add(var);
}
}
if (vars.size() > 0) {
// Create new equality sets for all of the non-equal vars
List<Equality> newInvs = sliceEquality.createEqualityInvs(vars, eq);
// Create new slices and invariants for each new leader
// copyInvsFromLeader(sliceEquality, leader, vars);
sliceEquality.copyInvsFromLeader(leader, vars);
// Keep track of all of the new invariants created.
// Add all of the new equality sets to our list
allNewInvs.addAll(newInvs);
}
}
sliceEquality.invs.addAll(allNewInvs);
}
}
}