001: //
002: // Copyright (C) 2005 United States Government as represented by the
003: // Administrator of the National Aeronautics and Space Administration
004: // (NASA). All Rights Reserved.
005: //
006: // This software is distributed under the NASA Open Source Agreement
007: // (NOSA), version 1.3. The NOSA has been approved by the Open Source
008: // Initiative. See the file NOSA-1.3-JPF at the top of the distribution
009: // directory tree for the complete NOSA document.
010: //
011: // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
012: // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
013: // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
014: // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
015: // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
016: // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
017: // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
018: //
019: //
020:
021: package gov.nasa.jpf.jvm;
022:
023: import java.io.BufferedReader;
024: import java.io.FileNotFoundException;
025: import java.io.FileReader;
026: import java.io.IOException;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.regex.Matcher;
031: import java.util.regex.Pattern;
032: import org.apache.bcel.classfile.JavaClass;
033: import org.apache.bcel.classfile.Method;
034:
035: /**
036: * A configuration file-driven attributor so that we can tailor JPF's
037: * attributor based on the application under test.
038: *
039: * The input file looks like:
040: * # This is a comment
041: * [atomic]
042: * <class regex> <method regex> (true|false)
043: * ...
044: * [relevance]
045: * <class regex> <method regex> (always|never|runnables|sync)
046: * ...
047: *
048: * @author Owen O'Malley
049: */
050: public class ConfigAttributor extends DefaultAttributor {
051:
052: public ConfigAttributor() {
053: try {
054: parse("jpf-attributes");
055: } catch (FileNotFoundException e) {
056: } catch (IOException e) {
057: System.err.println("IO exception reading attribute file: "
058: + e);
059: System.err.println("Ignoring file");
060: relevance_rules.clear();
061: atomic_rules.clear();
062: }
063: }
064:
065: public boolean isMethodAtomic(JavaClass jc, Method mth,
066: String uniqueName) {
067: String cls = jc.getClassName();
068: Iterator itr = atomic_rules.iterator();
069: while (itr.hasNext()) {
070: NameRule rule = (NameRule) itr.next();
071: if (rule.isMatch(cls, uniqueName)) {
072: System.out.println("Found atomic rule for " + cls + ":"
073: + uniqueName);
074: return rule.getResult() == 1;
075: }
076: }
077: // if no rules matched, use the default rules
078: return super .isMethodAtomic(jc, mth, uniqueName);
079: }
080:
081: /**
082: * is calling a certain method in the context of multiple runnable threads
083: * scheduling relevant (i.e. has to be considered as a step boundary
084: */
085: public int getSchedulingRelevance(JavaClass jc, Method mth,
086: String uniqueName) {
087: String cls = jc.getClassName();
088: Iterator itr = relevance_rules.iterator();
089: while (itr.hasNext()) {
090: NameRule rule = (NameRule) itr.next();
091: if (rule.isMatch(cls, uniqueName)) {
092: int result = rule.getResult();
093: System.out.println("Found scheduling rule for " + cls
094: + ":" + uniqueName + " = " + result);
095: return result;
096: }
097: }
098: // if no rules matched, use the default rules
099: return super .getSchedulingRelevance(jc, mth, uniqueName);
100: }
101:
102: private void parse(String filename) throws FileNotFoundException,
103: IOException {
104: BufferedReader config_file = new BufferedReader(new FileReader(
105: filename));
106: System.out.println("Using JPF attributes from " + filename);
107: String line = config_file.readLine();
108: String current_section = null;
109: while (line != null) {
110: line = line.trim();
111: if (line.length() != 0 && line.charAt(0) != '#') {
112: if (line.charAt(0) == '[') {
113: current_section = parseSection(line);
114: } else if ("relevance".equals(current_section)) {
115: parseRelevanceRule(line);
116: } else if ("atomic".equals(current_section)) {
117: parseAtomicRule(line);
118: } else {
119: System.err.println("Rules found in section "
120: + current_section + ", which is unknown.");
121: }
122: }
123: line = config_file.readLine();
124: }
125: }
126:
127: private static final Pattern section_pattern = Pattern
128: .compile("\\[([a-zA-Z]+)\\]");
129:
130: private String parseSection(String line) {
131: Matcher match = section_pattern.matcher(line);
132: if (match.matches()) {
133: return match.group(1);
134: }
135: System.err.println("Problem parsing section name " + line);
136: return null;
137: }
138:
139: private static final Pattern relevance_rule_pattern = Pattern
140: .compile("([^ ]+) +([^ ]+) +(always|never|neverbody|runnables|sync)");
141:
142: private void parseRelevanceRule(String line) {
143: Matcher match = relevance_rule_pattern.matcher(line);
144: if (match.matches()) {
145: int result = 0;
146: String value = match.group(3);
147: if ("always".equals(value)) {
148: result = MethodInfo.SR_ALWAYS;
149: } else if ("never".equals(value)) {
150: result = MethodInfo.SR_NEVER;
151: } else if ("neverbody".equals(value)) {
152: result = MethodInfo.SR_NEVERBODY;
153: } else if ("runnables".equals(value)) {
154: result = MethodInfo.SR_RUNNABLES;
155: } else if ("sync".equals(value)) {
156: result = MethodInfo.SR_SYNC;
157: } else {
158: System.err.println("Unknown relevance value: " + value);
159: return;
160: }
161: relevance_rules.add(new NameRule(match.group(1), match
162: .group(2), result));
163: } else {
164: System.err.println("Relevance rule parse error on line: "
165: + line);
166: }
167: }
168:
169: private static final Pattern atomic_rule_pattern = Pattern
170: .compile("([^ ]+) +([^ ]+) +(true|false)");
171:
172: private void parseAtomicRule(String line) {
173: Matcher match = atomic_rule_pattern.matcher(line);
174: if (match.matches()) {
175: int result = 0;
176: String value = match.group(3);
177: if ("true".equals(value)) {
178: result = 1;
179: } else if ("false".equals(value)) {
180: result = 0;
181: } else {
182: System.err.println("Unknown atomic value: " + value);
183: return;
184: }
185: atomic_rules.add(new NameRule(match.group(1), match
186: .group(2), result));
187: } else {
188: System.err.println("Atomic rule parse error on line: "
189: + line);
190: }
191: }
192:
193: /**
194: * A rule that contains two regular expressions that will take two strings
195: * and report if they match the rule.
196: * It also stores the result that needs to be returned if this rule matches.
197: */
198: private static class NameRule {
199: NameRule(String class_pattern_string,
200: String method_pattern_string, int value) {
201: class_pattern = Pattern.compile(class_pattern_string);
202: method_pattern = Pattern.compile(method_pattern_string);
203: result = value;
204: }
205:
206: boolean isMatch(String class_name, String method_name) {
207: Matcher class_match = class_pattern.matcher(class_name);
208: if (class_match.matches()) {
209: return method_pattern.matcher(method_name).matches();
210: }
211: return false;
212: }
213:
214: int getResult() {
215: return result;
216: }
217:
218: Pattern class_pattern;
219: Pattern method_pattern;
220: int result;
221: }
222:
223: private List relevance_rules = new ArrayList();
224: private List atomic_rules = new ArrayList();
225: }
|