Newer
Older
MagnetRON / src / org / ntlab / trace / Trace.java
  1. package org.ntlab.trace;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.FileReader;
  5. import java.io.IOException;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.HashSet;
  9. import java.util.Iterator;
  10. import java.util.Stack;
  11.  
  12. public class Trace {
  13. protected static final boolean EAGER_DETECTION_OF_ARRAY_SET = false; // 配列要素への代入の検出を多く見積もるか?(多く見積もるとFalse Positiveになる可能性がある)
  14. protected static Trace theTrace = null;
  15. protected HashMap<String, ThreadInstance> threads = new HashMap<String, ThreadInstance>();
  16.  
  17. protected Trace() {
  18. }
  19. /**
  20. * 指定したPlainTextのトレースファイルを解読して Trace オブジェクトを生成する
  21. * @param file トレースファイル
  22. */
  23. public Trace(BufferedReader file) {
  24. try {
  25. read(file);
  26. file.close();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. /**
  32. * 指定したPlainTextのトレースファイルを解読して Trace オブジェクトを生成する
  33. * @param traceFile トレースファイルのパス
  34. */
  35. public Trace(String traceFile) {
  36. BufferedReader file;
  37. try {
  38. file = new BufferedReader(new FileReader(traceFile));
  39. read(file);
  40. file.close();
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45.  
  46. private void read(BufferedReader file) throws IOException {
  47. // トレースファイル読み込み
  48. String line, prevLine = null;
  49. String signature;
  50. String callerSideSignature;
  51. String threadNo = null;
  52. String[] methodData;
  53. String[] argData;
  54. String[] returnData;
  55. String[] accessData;
  56. String[] updateData;
  57. String thisObjectId;
  58. String thisClassName;
  59. boolean isConstractor = false;
  60. boolean isCollectionType = false;
  61. boolean isStatic = false;
  62. long timeStamp = 0L;
  63. ThreadInstance thread = null;
  64. HashMap<String, Stack<String>> stacks = new HashMap<String, Stack<String>>();
  65. while ((line = file.readLine()) != null) {
  66. // トレースファイルの解析
  67. if (line.startsWith("Method")) {
  68. // メソッド呼び出し(コンストラクタ呼び出しも含む)
  69. methodData = line.split(":");
  70. int n = methodData[0].indexOf(',');
  71. signature = methodData[0].substring(n + 1);
  72. threadNo = methodData[methodData.length - 1].split(" ")[1];
  73. thisObjectId = methodData[1];
  74. thisClassName = methodData[0].substring(0, n).split(" ")[1];
  75. isConstractor = false;
  76. isStatic = false;
  77. if (signature.contains("static ")) {
  78. isStatic = true;
  79. }
  80. callerSideSignature = signature;
  81. timeStamp = Long.parseLong(methodData[methodData.length - 2]);
  82. if (prevLine != null) {
  83. if (prevLine.startsWith("New")) {
  84. isConstractor = true;
  85. } else if (prevLine.startsWith("Invoke")) {
  86. callerSideSignature = prevLine.split(":")[1];
  87. }
  88. }
  89. thread = threads.get(threadNo);
  90. Stack<String> stack;
  91. if (thread == null) {
  92. thread = new ThreadInstance(threadNo);
  93. threads.put(threadNo, thread);
  94. stack = new Stack<String>();
  95. stacks.put(threadNo, stack);
  96. } else {
  97. stack = stacks.get(threadNo);
  98. }
  99. stack.push(line);
  100. thread.callMethod(signature, callerSideSignature, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp);
  101. } else if (line.startsWith("Args")) {
  102. // メソッド呼び出しの引数
  103. argData = line.split(":");
  104. threadNo = argData[argData.length - 1].split(" ")[1];
  105. thread = threads.get(threadNo);
  106. ArrayList<ObjectReference> arguments = new ArrayList<ObjectReference>();
  107. for (int k = 1; k < argData.length - 2; k += 2) {
  108. arguments.add(new ObjectReference(argData[k+1], argData[k]));
  109. }
  110. thread.setArgments(arguments);
  111. } else if (line.startsWith("Return")) {
  112. // メソッドからの復帰
  113. returnData = line.split(":");
  114. threadNo = returnData[returnData.length - 1].split(" ")[1];
  115. Stack<String> stack = stacks.get(threadNo);
  116. if (!stack.isEmpty()) {
  117. String line2 = stack.peek();
  118. if (line2.split("\\(")[0].endsWith(line.split("\\(")[1])) {
  119. stack.pop();
  120. } else {
  121. do {
  122. stack.pop();
  123. thread.terminateMethod();
  124. line2 = stack.peek();
  125. } while (!stack.isEmpty() && !line2.split("\\(")[0].endsWith(line.split("\\(")[1]));
  126. if (!stack.isEmpty()) stack.pop();
  127. }
  128. thread = threads.get(threadNo);
  129. ObjectReference returnValue = new ObjectReference(returnData[2], returnData[1]);
  130. thisObjectId = returnData[2];
  131. isCollectionType = false;
  132. String curLine = returnData[0];
  133. if(curLine.contains("Return call(List")
  134. || curLine.contains("Return call(Vector")
  135. || curLine.contains("Return call(Iterator")
  136. || curLine.contains("Return call(ListIterator")
  137. || curLine.contains("Return call(ArrayList")
  138. || curLine.contains("Return call(Stack")
  139. || curLine.contains("Return call(Hash")
  140. || curLine.contains("Return call(Map")
  141. || curLine.contains("Return call(Set")
  142. || curLine.contains("Return call(Linked")
  143. || curLine.contains("Return call(Collection")
  144. || curLine.contains("Return call(Arrays")
  145. || curLine.contains("Return call(Thread")) {
  146. isCollectionType = true;
  147. }
  148. thread.returnMethod(returnValue, thisObjectId, isCollectionType);
  149. }
  150. } else if (line.startsWith("get")) {
  151. // フィールドアクセス
  152. accessData = line.split(":");
  153. threadNo = accessData[8].split(" ")[1];
  154. thread = threads.get(threadNo);
  155. if (thread != null) thread.fieldAccess(accessData[5], accessData[6], accessData[3], accessData[4], accessData[1], accessData[2]);
  156. } else if (line.startsWith("set")) {
  157. // フィールド更新
  158. updateData = line.split(":");
  159. threadNo = updateData[6].split(" ")[1];
  160. thread = threads.get(threadNo);
  161. if (thread != null) thread.fieldUpdate(updateData[3], updateData[4], updateData[1], updateData[2]);
  162. }
  163. prevLine = line;
  164. }
  165. }
  166. /**
  167. * オンライン解析用シングルトンの取得
  168. * @return オンライン解析用トレース
  169. */
  170. public static Trace getInstance() {
  171. if (theTrace == null) {
  172. theTrace = new Trace();
  173. }
  174. return theTrace;
  175. }
  176. /**
  177. * スレッドIDを指定してスレッドインスタンスを取得する(オンライン解析用)
  178. * @param threadId
  179. * @return スレッドインスタンス
  180. */
  181. public static ThreadInstance getThreadInstance(String threadId) {
  182. return getInstance().threads.get(threadId);
  183. }
  184. /**
  185. * 指定したスレッド上で現在実行中のメソッド実行を取得する(オンライン解析用)
  186. * @param thread 対象スレッド
  187. * @return thread 上で現在実行中のメソッド実行
  188. */
  189. public static MethodExecution getCurrentMethodExecution(Thread thread) {
  190. ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId()));
  191. return t.getCurrentMethodExecution();
  192. }
  193. /**
  194. * 指定したスレッド上で現在実行中のトレースポイントを取得する(オンライン解析用)
  195. * @param thread 対象スレッド
  196. * @return thread 上で現在実行中の実行文のトレースポイント
  197. */
  198. public static TracePoint getCurrentTracePoint(Thread thread) {
  199. ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId()));
  200. return t.getCurrentTracePoint();
  201. }
  202. /**
  203. * 全スレッドを取得する
  204. * @return スレッドIDからスレッドインスタンスへのマップ
  205. */
  206. public HashMap<String, ThreadInstance> getAllThreads() {
  207. return threads;
  208. }
  209.  
  210. /**
  211. * メソッド毎に全メソッド実行を全てのスレッドから取り出す
  212. * @return メソッドシグニチャからメソッド実行のリストへのHashMap
  213. */
  214. public HashMap<String, ArrayList<MethodExecution>> getAllMethodExecutions() {
  215. Iterator<String> threadsIterator = threads.keySet().iterator();
  216. final HashMap<String, ArrayList<MethodExecution>> results = new HashMap<>();
  217. for (; threadsIterator.hasNext();) {
  218. ThreadInstance thread = threads.get(threadsIterator.next());
  219. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  220. @Override
  221. public boolean preVisitThread(ThreadInstance thread) {
  222. return false;
  223. }
  224. @Override
  225. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  226. String signature = methodExecution.getSignature();
  227. ArrayList<MethodExecution> executions = results.get(signature);
  228. if (executions == null) {
  229. executions = new ArrayList<>();
  230. results.put(signature, executions);
  231. }
  232. executions.add(methodExecution);
  233. return false;
  234. }
  235. @Override
  236. public boolean postVisitThread(ThreadInstance thread) {
  237. return false;
  238. }
  239. @Override
  240. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  241. return false;
  242. }
  243. });
  244. }
  245. return results;
  246. }
  247. /**
  248. * 全メソッドのシグニチャを取得する
  249. * @return 全メソッドシグニチャ
  250. */
  251. public HashSet<String> getAllMethodSignatures() {
  252. final HashSet<String> signatures = new HashSet<String>();
  253. Iterator<String> threadsIterator = threads.keySet().iterator();
  254. for (; threadsIterator.hasNext();) {
  255. ThreadInstance thread = threads.get(threadsIterator.next());
  256. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  257. @Override
  258. public boolean preVisitThread(ThreadInstance thread) {
  259. return false;
  260. }
  261. @Override
  262. public boolean postVisitThread(ThreadInstance thread) {
  263. return false;
  264. }
  265. @Override
  266. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  267. signatures.add(methodExecution.getSignature());
  268. return false;
  269. }
  270. @Override
  271. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  272. return false;
  273. }
  274. });
  275. }
  276. return signatures;
  277. }
  278. /**
  279. * メソッド名が methodSignature に前方一致するメソッド実行を全てのスレッドから取り出す
  280. * @param methodSignature 検索文字列
  281. * @return 一致した全メソッド実行
  282. */
  283. public ArrayList<MethodExecution> getMethodExecutions(final String methodSignature) {
  284. Iterator<String> threadsIterator = threads.keySet().iterator();
  285. final ArrayList<MethodExecution> results = new ArrayList<MethodExecution>();
  286. for (; threadsIterator.hasNext();) {
  287. ThreadInstance thread = threads.get(threadsIterator.next());
  288. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  289. @Override
  290. public boolean preVisitThread(ThreadInstance thread) {
  291. return false;
  292. }
  293. @Override
  294. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  295. if (methodExecution.getSignature().startsWith(methodSignature)) {
  296. results.add(methodExecution);
  297. }
  298. return false;
  299. }
  300. @Override
  301. public boolean postVisitThread(ThreadInstance thread) {
  302. return false;
  303. }
  304. @Override
  305. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  306. return false;
  307. }
  308. });
  309. }
  310. return results;
  311. }
  312.  
  313. /**
  314. * methodSignature に前方一致するメソッド名を持つメソッドの最後の実行
  315. * @param methodSignature メソッド名(前方一致で検索する)
  316. * @return 該当する最後のメソッド実行
  317. */
  318. public MethodExecution getLastMethodExecution(final String methodSignature) {
  319. return traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() {
  320. @Override
  321. public boolean preVisitThread(ThreadInstance thread) { return false; }
  322. @Override
  323. public boolean postVisitThread(ThreadInstance thread) { return false; }
  324. @Override
  325. public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; }
  326. @Override
  327. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  328. if (methodExecution.getSignature().startsWith(methodSignature)) return true;
  329. return false;
  330. }
  331. });
  332. }
  333.  
  334. /**
  335. * methodSignature に前方一致するメソッド名を持つメソッドの before 以前の最後の実行
  336. * @param methodSignature メソッド名(前方一致で検索する)
  337. * @param before 探索開始トレースポイント(これより以前を探索)
  338. * @return 該当する最後のメソッド実行
  339. */
  340. public MethodExecution getLastMethodExecution(final String methodSignature, TracePoint before) {
  341. return traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() {
  342. @Override
  343. public boolean preVisitThread(ThreadInstance thread) { return false; }
  344. @Override
  345. public boolean postVisitThread(ThreadInstance thread) { return false; }
  346. @Override
  347. public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; }
  348. @Override
  349. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  350. if (methodExecution.getSignature().startsWith(methodSignature)) return true;
  351. return false;
  352. }
  353. }, before);
  354. }
  355. /**
  356. * マーク内で実行が開始された全メソッドのシグニチャを取得する
  357. * @param markStart マークの開始時刻
  358. * @param markEnd マークの終了時刻
  359. * @return 該当するメソッドシグニチャ
  360. */
  361. public HashSet<String> getMarkedMethodSignatures(final long markStart, final long markEnd) {
  362. final HashSet<String> signatures = new HashSet<String>();
  363. Iterator<String> threadsIterator = threads.keySet().iterator();
  364. for (; threadsIterator.hasNext();) {
  365. ThreadInstance thread = threads.get(threadsIterator.next());
  366. thread.traverseMarkedMethodExecutions(new IMethodExecutionVisitor() {
  367. @Override
  368. public boolean preVisitThread(ThreadInstance thread) {
  369. return false;
  370. }
  371. @Override
  372. public boolean postVisitThread(ThreadInstance thread) {
  373. return false;
  374. }
  375. @Override
  376. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  377. signatures.add(methodExecution.getSignature());
  378. return false;
  379. }
  380. @Override
  381. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  382. return false;
  383. }
  384. }, markStart, markEnd);
  385. }
  386. return signatures;
  387. }
  388. /**
  389. * マーク内で実行が開始された全メソッド実行をメソッド毎に取得する
  390. * @param markStart マークの開始時刻
  391. * @param markEnd マークの終了時刻
  392. * @return メソッドシグニチャから該当するメソッド実行のリストへのHashMap
  393. */
  394. public HashMap<String, ArrayList<MethodExecution>> getMarkedMethodExecutions(final long markStart, final long markEnd) {
  395. final HashMap<String, ArrayList<MethodExecution>>allExecutions = new HashMap<>();
  396. Iterator<String> threadsIterator = threads.keySet().iterator();
  397. for (; threadsIterator.hasNext();) {
  398. ThreadInstance thread = threads.get(threadsIterator.next());
  399. thread.traverseMarkedMethodExecutions(new IMethodExecutionVisitor() {
  400. @Override
  401. public boolean preVisitThread(ThreadInstance thread) {
  402. return false;
  403. }
  404. @Override
  405. public boolean postVisitThread(ThreadInstance thread) {
  406. return false;
  407. }
  408. @Override
  409. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  410. ArrayList<MethodExecution> executions = allExecutions.get(methodExecution.getSignature());
  411. if (executions == null) {
  412. executions = new ArrayList<>();
  413. allExecutions.put(methodExecution.getSignature(), executions);
  414. }
  415. executions.add(methodExecution);
  416. return false;
  417. }
  418. @Override
  419. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  420. return false;
  421. }
  422. }, markStart, markEnd);
  423. }
  424. return allExecutions;
  425. }
  426. /**
  427. * マーク外で実行が開始された全メソッドのシグニチャを取得する
  428. * @param markStart マークの開始時刻
  429. * @param markEnd マークの終了時刻
  430. * @return 該当するメソッドシグニチャ
  431. */
  432. public HashSet<String> getUnmarkedMethodSignatures(long markStart, long markEnd) {
  433. HashSet<String> signatures = new HashSet<String>();
  434. Iterator<String> threadsIterator = threads.keySet().iterator();
  435. for (; threadsIterator.hasNext();) {
  436. ThreadInstance thread = threads.get(threadsIterator.next());
  437. thread.getUnmarkedMethodSignatures(signatures, markStart, markEnd);
  438. }
  439. return signatures;
  440. }
  441. /**
  442. * マーク外で実行が開始された全メソッド実行を取得する
  443. * @param markStart マークの開始時刻
  444. * @param markEnd マークの終了時刻
  445. * @return メソッドシグニチャから該当するメソッド実行のリストへのHashMap
  446. */
  447. public HashMap<String, ArrayList<MethodExecution>> getUnmarkedMethodExecutions(long markStart, long markEnd) {
  448. HashMap<String, ArrayList<MethodExecution>> executions = new HashMap<>();
  449. Iterator<String> threadsIterator = threads.keySet().iterator();
  450. for (; threadsIterator.hasNext();) {
  451. ThreadInstance thread = threads.get(threadsIterator.next());
  452. thread.getUnmarkedMethodExecutions(executions, markStart, markEnd);
  453. }
  454. return executions;
  455. }
  456. protected TracePoint getLastMethodEntryInThread(ArrayList<MethodExecution> rootExecutions) {
  457. MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1);
  458. return getLastMethodEntryInThread(rootExecutions, lastExecution.getExitOutPoint());
  459. }
  460.  
  461. protected TracePoint getLastMethodEntryInThread(ArrayList<MethodExecution> rootExecutions, TracePoint start) {
  462. return getLastMethodEntryInThread(rootExecutions, start, -1L);
  463. }
  464. /**
  465. *
  466. * @param rootExecutions
  467. * @param start
  468. * @param before
  469. * @return
  470. */
  471. protected TracePoint getLastMethodEntryInThread(ArrayList<MethodExecution> rootExecutions, TracePoint start, final long before) {
  472. final TracePoint cp[] = new TracePoint[1];
  473. cp[0] = start;
  474. for (;;) {
  475. if (!cp[0].isStepBackOut() && traverseMethodExecutionsInCallTreeBackward (
  476. new IMethodExecutionVisitor() {
  477. @Override
  478. public boolean preVisitThread(ThreadInstance thread) { return false; }
  479. @Override
  480. public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; }
  481. @Override
  482. public boolean postVisitThread(ThreadInstance thread) { return false; }
  483. @Override
  484. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  485. if (methodExecution.getEntryTime() < before || before == -1L) {
  486. cp[0] = methodExecution.getEntryPoint();
  487. return true;
  488. }
  489. return false;
  490. }
  491. }, cp[0])) {
  492. return cp[0];
  493. }
  494. if (rootExecutions.size() == 0) break;
  495. MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1);
  496. cp[0] = lastExecution.getExitOutPoint();
  497. }
  498. return null;
  499. }
  500. public boolean getLastStatementInThread(String threadId, final TracePoint[] start, final IStatementVisitor visitor) {
  501. return getLastStatementInThread((ArrayList<MethodExecution>) threads.get(threadId).getRoot().clone(), start, start[0].getStatement().getTimeStamp(), visitor);
  502. }
  503. protected boolean getLastStatementInThread(ArrayList<MethodExecution> rootExecutions, final TracePoint[] start, final long before, final IStatementVisitor visitor) {
  504. final boolean[] bArrived = new boolean[] {
  505. false
  506. };
  507. for (;;) {
  508. if (start[0].isValid() && traverseStatementsInCallTreeBackward(
  509. new IStatementVisitor() {
  510. @Override
  511. public boolean preVisitStatement(Statement statement) {
  512. if (statement instanceof MethodInvocation) {
  513. MethodExecution methodExecution = ((MethodInvocation) statement).getCalledMethodExecution();
  514. if ((!methodExecution.isTerminated() && methodExecution.getExitTime() < before) || before == -1L) {
  515. if (visitor.preVisitStatement(statement)) return true;
  516. bArrived[0] = true;
  517. return true;
  518. }
  519. } else {
  520. if (statement.getTimeStamp() < before || before == -1L) {
  521. if (visitor.preVisitStatement(statement)) return true;
  522. bArrived[0] = true;
  523. return true;
  524. }
  525. }
  526. return visitor.preVisitStatement(statement);
  527. }
  528. @Override
  529. public boolean postVisitStatement(Statement statement) {
  530. return visitor.postVisitStatement(statement);
  531. }
  532. }, start[0])) {
  533. return !bArrived[0];
  534. }
  535. if (rootExecutions.size() == 0) break;
  536. MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1);
  537. start[0] = lastExecution.getExitPoint();
  538. }
  539. start[0] = null;
  540. return false;
  541. }
  542. public TracePoint getLastTracePoint() {
  543. TracePoint tp = null;
  544. for (ThreadInstance thread: threads.values()) {
  545. if (tp == null || thread.getLastTracePoint().getStatement().getTimeStamp() > tp.getStatement().getTimeStamp()) {
  546. tp = thread.getLastTracePoint();
  547. }
  548. }
  549. return tp;
  550. }
  551.  
  552. public TracePoint getCreationTracePoint(final ObjectReference newObjectId, TracePoint before) {
  553. if (before != null) before = before.duplicate();
  554. before = traverseStatementsInTraceBackward(
  555. new IStatementVisitor() {
  556. @Override
  557. public boolean preVisitStatement(Statement statement) {
  558. if (statement instanceof MethodInvocation) {
  559. MethodInvocation mi = (MethodInvocation)statement;
  560. if (mi.getCalledMethodExecution().isConstructor()
  561. && mi.getCalledMethodExecution().getReturnValue().equals(newObjectId)) {
  562. return true;
  563. }
  564. }
  565. return false;
  566. }
  567. @Override
  568. public boolean postVisitStatement(Statement statement) { return false; }
  569. }, before);
  570. if (before != null) {
  571. return before;
  572. }
  573. return null;
  574. }
  575.  
  576. public TracePoint getFieldUpdateTracePoint(final Reference ref, TracePoint before) {
  577. if (before != null) before = before.duplicate();
  578. final String srcType = ref.getSrcClassName();
  579. final String dstType = ref.getDstClassName();
  580. final String srcObjId = ref.getSrcObjectId();
  581. final String dstObjId = ref.getDstObjectId();
  582. before = traverseStatementsInTraceBackward(new IStatementVisitor() {
  583. @Override
  584. public boolean preVisitStatement(Statement statement) {
  585. if (statement instanceof FieldUpdate) {
  586. FieldUpdate fu = (FieldUpdate)statement;
  587. if (fu.getContainerObjId().equals(srcObjId)
  588. && fu.getValueObjId().equals(dstObjId)) {
  589. // オブジェクトIDが互いに一致した場合
  590. return true;
  591. } else if ((srcObjId == null || isNull(srcObjId)) && fu.getContainerClassName().equals(srcType)) {
  592. if ((dstObjId == null || isNull(dstObjId)) && fu.getValueClassName().equals(dstType)) {
  593. // ref にオブジェクトIDを指定していなかった場合
  594. ref.setSrcObjectId(fu.getContainerObjId());
  595. ref.setDstObjectId(fu.getValueObjId());
  596. return true;
  597. } else if (fu.getValueObjId().equals(dstObjId)) {
  598. // クラス変数への代入の場合
  599. ref.setSrcObjectId(srcObjId);
  600. ref.setDstClassName(dstType);
  601. return true;
  602. }
  603. }
  604. }
  605. return false;
  606. }
  607. @Override
  608. public boolean postVisitStatement(Statement statement) { return false; }
  609. }, before);
  610. if (before != null) {
  611. return before;
  612. }
  613. return null;
  614. }
  615.  
  616. public TracePoint getCollectionAddTracePoint(final Reference ref, TracePoint before) {
  617. final TracePoint[] result = new TracePoint[1];
  618. if (traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() {
  619. @Override
  620. public boolean preVisitThread(ThreadInstance thread) {
  621. return false;
  622. }
  623. @Override
  624. public boolean postVisitThread(ThreadInstance thread) {
  625. return false;
  626. }
  627. @Override
  628. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  629. return false;
  630. }
  631. @Override
  632. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  633. String srcType = ref.getSrcClassName();
  634. String dstType = ref.getDstClassName();
  635. String srcObjId = ref.getSrcObjectId();
  636. String dstObjId = ref.getDstObjectId();
  637. if (methodExecution.isCollectionType() && isCollectionAdd(methodExecution.getSignature())) {
  638. if (dstObjId != null && methodExecution.getThisObjId().equals(srcObjId)) {
  639. ArrayList<ObjectReference> args = methodExecution.getArguments();
  640. for (int i = 0; i < args.size(); i++) {
  641. ObjectReference arg = args.get(i);
  642. if (arg.getId().equals(dstObjId)) {
  643. ref.setSrcClassName(methodExecution.getThisClassName());
  644. ref.setDstClassName(arg.getActualType());
  645. result[0] = methodExecution.getCallerTracePoint();
  646. return true;
  647. }
  648. }
  649. } else if (dstObjId == null && methodExecution.getThisClassName().equals(srcType)) {
  650. ArrayList<ObjectReference> args = methodExecution.getArguments();
  651. for (int i = 0; i < args.size(); i++) {
  652. ObjectReference arg = args.get(i);
  653. if (arg.getActualType().equals(dstType)) {
  654. ref.setSrcObjectId(methodExecution.getThisObjId());
  655. ref.setDstObjectId(arg.getId());
  656. result[0] = methodExecution.getCallerTracePoint();
  657. return true;
  658. }
  659. }
  660. }
  661. }
  662. return false;
  663. }
  664. }, before) != null) {
  665. return result[0];
  666. }
  667. return null;
  668. }
  669.  
  670. public TracePoint getArraySetTracePoint(final Reference ref, TracePoint before) {
  671. final TracePoint start = (before == null) ? null : before.duplicate();
  672. before = traverseStatementsInTraceBackward(new IStatementVisitor() {
  673. @Override
  674. public boolean preVisitStatement(Statement statement) {
  675. if (statement instanceof FieldAccess) {
  676. if (isArraySet(ref, start)) {
  677. return true;
  678. }
  679. }
  680. return false;
  681. }
  682. @Override
  683. public boolean postVisitStatement(Statement statement) { return false; }
  684. }, start);
  685. if (before != null) {
  686. return before;
  687. }
  688. return null;
  689. }
  690. private boolean isCollectionAdd(String methodSignature) {
  691. return (methodSignature.contains("add(") || methodSignature.contains("set(") || methodSignature.contains("put(") || methodSignature.contains("push(") || methodSignature.contains("addElement("));
  692. }
  693. private boolean isArraySet(Reference ref, TracePoint fieldAccessPoint) {
  694. FieldAccess fieldAccess = (FieldAccess)fieldAccessPoint.getStatement();
  695. String srcObjId = ref.getSrcObjectId();
  696. String dstObjId = ref.getDstObjectId();
  697. if (fieldAccess.getValueClassName().startsWith("[L")
  698. && fieldAccess.getValueObjId().equals(srcObjId)) {
  699. // srcId は配列
  700. // メソッド実行開始から fieldAccessPoint までの間のメソッド実行中で dstId が出現したか?
  701. TracePoint p = fieldAccessPoint.duplicate();
  702. while (p.stepBackOver()) {
  703. Statement statement = p.getStatement();
  704. if (statement instanceof MethodInvocation) {
  705. MethodExecution calledMethod = ((MethodInvocation)statement).getCalledMethodExecution();
  706. if (calledMethod.getReturnValue().getId().equals(dstObjId)) {
  707. // dstId は戻り値として出現
  708. ref.setSrcClassName(fieldAccess.getValueClassName());
  709. ref.setDstClassName(calledMethod.getReturnValue().getActualType());
  710. return true;
  711. } else if (dstObjId == null || isNull(dstObjId) && calledMethod.getReturnValue().getActualType().equals(ref.getDstClassName())) {
  712. // dstClassName は戻り値の型として出現
  713. ref.setSrcObjectId(fieldAccess.getValueObjId());
  714. ref.setDstObjectId(calledMethod.getReturnValue().getId());
  715. return true;
  716. }
  717. }
  718. if (EAGER_DETECTION_OF_ARRAY_SET) {
  719. if (statement instanceof FieldAccess) {
  720. if (((FieldAccess)statement).getContainerObjId().equals(dstObjId)) {
  721. // dstId はフィールドに出現
  722. ref.setSrcClassName(fieldAccess.getValueClassName());
  723. ref.setDstClassName(((FieldAccess)statement).getContainerClassName());
  724. return true;
  725. } else if (dstObjId == null || isNull(dstObjId) && ((FieldAccess)statement).getContainerClassName().equals(ref.getDstClassName())) {
  726. // dstClassName はフィールドの型として出現
  727. ref.setSrcObjectId(fieldAccess.getValueObjId());
  728. ref.setDstObjectId(((FieldAccess)statement).getContainerObjId());
  729. return true;
  730. }
  731. }
  732. }
  733. }
  734. ArrayList<ObjectReference> args = fieldAccessPoint.getMethodExecution().getArguments();
  735. int argindex = args.indexOf(new ObjectReference(dstObjId));
  736. if (argindex != -1) {
  737. // dstId は引数に出現
  738. ref.setSrcClassName(fieldAccess.getValueClassName());
  739. ref.setDstClassName(args.get(argindex).getActualType());
  740. return true;
  741. } else if (dstObjId == null || isNull(dstObjId)) {
  742. for (int j = 0; j < args.size(); j++) {
  743. if (args.get(j).getActualType().equals(ref.getDstClassName())) {
  744. // dstClassName は引数の型に出現
  745. ref.setSrcObjectId(fieldAccess.getValueObjId());
  746. ref.setDstObjectId(args.get(j).getId());
  747. return true;
  748. }
  749. }
  750. }
  751. }
  752. return false;
  753. }
  754. /**
  755. * トレース中の全メソッド実行の開始地点を逆向きに探索する
  756. * @param visitor メソッド実行のビジター(postVisitMethodExecution()しか呼び返さないので注意)
  757. * @return 中断したメソッド実行
  758. */
  759. public MethodExecution traverseMethodEntriesInTraceBackward(IMethodExecutionVisitor visitor) {
  760. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  761. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  762. // 各スレッドにおいて一番最後に開始したメソッド実行を探す
  763. long traceLastTime = 0;
  764. String traceLastThread = null;
  765. long traceLastTime2 = 0;
  766. String traceLastThread2 = null;
  767. for (String threadId: threads.keySet()) {
  768. ThreadInstance thread = threads.get(threadId);
  769. ArrayList<MethodExecution> rootExecutions = (ArrayList<MethodExecution>)thread.getRoot().clone();
  770. threadRoots.put(threadId, rootExecutions);
  771. TracePoint threadLastTp = getLastMethodEntryInThread(rootExecutions);
  772. threadLastPoints.put(threadId, threadLastTp);
  773. if (threadLastTp != null) {
  774. long threadLastTime = threadLastTp.getMethodExecution().getEntryTime();
  775. if (traceLastTime < threadLastTime) {
  776. traceLastTime2 = traceLastTime;
  777. traceLastThread2 = traceLastThread;
  778. traceLastTime = threadLastTime;
  779. traceLastThread = threadId;
  780. }
  781. }
  782. }
  783. return traverseMethodEntriesInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  784. }
  785. /**
  786. * 指定した実行時点以前に実行が開始されたメソッド実行の開始時点を逆向きに探索する
  787. * @param visitor メソッド実行のビジター(postVisitMethodExecution()しか呼び返さないので注意)
  788. * @param before 探索開始時点
  789. * @return 中断したメソッド実行
  790. */
  791. public MethodExecution traverseMethodEntriesInTraceBackward(IMethodExecutionVisitor visitor, TracePoint before) {
  792. if (before == null) {
  793. return traverseMethodEntriesInTraceBackward(visitor);
  794. }
  795. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  796. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  797. String traceLastThread = null;
  798. long traceLastTime2 = 0;
  799. String traceLastThread2 = null;
  800. ThreadInstance thread = threads.get(before.getStatement().getThreadNo());
  801. ArrayList<MethodExecution> rootExecutions = (ArrayList<MethodExecution>)thread.getRoot().clone();
  802. for (int n = rootExecutions.size() - 1; n >= 0; n--) {
  803. MethodExecution root = rootExecutions.get(n);
  804. if (root.getEntryTime() > before.getMethodExecution().getEntryTime()) {
  805. rootExecutions.remove(n);
  806. } else {
  807. break;
  808. }
  809. }
  810. if (rootExecutions.size() > 0) {
  811. rootExecutions.remove(rootExecutions.size() - 1);
  812. }
  813. before = getLastMethodEntryInThread(rootExecutions, before);
  814. for (String threadId: threads.keySet()) {
  815. ThreadInstance t = threads.get(threadId);
  816. if (t == thread) {
  817. threadRoots.put(threadId, rootExecutions);
  818. traceLastThread = threadId;
  819. threadLastPoints.put(threadId, before);
  820. } else {
  821. ArrayList<MethodExecution> rootExes = (ArrayList<MethodExecution>)t.getRoot().clone();
  822. threadRoots.put(threadId, rootExes);
  823. MethodExecution threadLastExecution = rootExes.remove(rootExes.size() - 1);
  824. TracePoint threadBeforeTp = getLastMethodEntryInThread(rootExes, threadLastExecution.getExitOutPoint(), before.getMethodExecution().getEntryTime());
  825. threadLastPoints.put(threadId, threadBeforeTp);
  826. if (threadBeforeTp != null) {
  827. long threadLastTime = threadBeforeTp.getMethodExecution().getEntryTime();
  828. if (traceLastTime2 < threadLastTime) {
  829. traceLastTime2 = threadLastTime;
  830. traceLastThread2 = threadId;
  831. }
  832. }
  833. }
  834. }
  835. return traverseMethodEntriesInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  836. }
  837. private MethodExecution traverseMethodEntriesInTraceBackwardSub(
  838. final IMethodExecutionVisitor visitor,
  839. HashMap<String, ArrayList<MethodExecution>> threadRoots, HashMap<String, TracePoint> threadLastPoints,
  840. String traceLastThread, String traceLastThread2, long traceLastTime2) {
  841. // 全スレッドの同期をとりながら逆向きにメソッド実行を探索する
  842. for (;;) {
  843. // 探索対象のスレッド内の逆向き探索
  844. TracePoint threadLastTp = threadLastPoints.get(traceLastThread);
  845. MethodExecution threadLastExecution = threadLastTp.getMethodExecution();
  846. do {
  847. threadLastTp.stepBackOver();
  848. // そのスレッドの次のメソッド実行開始時点まで探索する
  849. threadLastTp = getLastMethodEntryInThread(threadRoots.get(traceLastThread), threadLastTp);
  850. if (threadLastTp == null) break;
  851. if (visitor.postVisitMethodExecution(threadLastExecution, threadLastExecution.getChildren())) {
  852. // 該当するメソッド実行を見つけた
  853. return threadLastExecution;
  854. }
  855. threadLastExecution = threadLastTp.getMethodExecution();
  856. } while (threadLastExecution.getEntryTime() > traceLastTime2);
  857. threadLastPoints.put(traceLastThread, threadLastTp);
  858. traceLastThread = traceLastThread2;
  859. // 次の次に探索すべきスレッド(未探索の領域が一番最後まで残っているスレッド)を決定する
  860. traceLastTime2 = 0;
  861. traceLastThread2 = null;
  862. boolean continueTraverse = false;
  863. for (String threadId: threadLastPoints.keySet()) {
  864. if (!threadId.equals(traceLastThread)) {
  865. TracePoint lastTp = threadLastPoints.get(threadId);
  866. if (lastTp != null) {
  867. continueTraverse = true;
  868. long threadLastTime = lastTp.getMethodExecution().getEntryTime();
  869. if (traceLastTime2 < threadLastTime) {
  870. traceLastTime2 = threadLastTime;
  871. traceLastThread2 = threadId;
  872. }
  873. }
  874. }
  875. }
  876. if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break;
  877. }
  878. return null;
  879. }
  880. /**
  881. * 呼び出し時の時刻が markStart から markEnd の間にある全スレッド中の全メソッド実行を探索する
  882. * @param visitor ビジター
  883. * @param markStart 開始時刻
  884. * @param markEnd 終了時刻
  885. */
  886. public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) {
  887. for (String threadId: threads.keySet()) {
  888. ThreadInstance thread = threads.get(threadId);
  889. thread.traverseMarkedMethodExecutions(visitor, markStart, markEnd);
  890. }
  891. }
  892. /**
  893. * トレース内の全スレッドを同期させならが全実行文を順方向に探索する
  894. *
  895. * @param visitor 実行文のビジター
  896. * @return 中断したトレースポイント
  897. */
  898. public TracePoint traverseStatementsInTrace(IStatementVisitor visitor) {
  899. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  900. HashMap<String, TracePoint> threadCurPoints = new HashMap<String, TracePoint>();
  901. // 各スレッドにおいて一番最初に開始したメソッド実行を探す
  902. long traceCurTime = -1;
  903. String traceCurThread = null;
  904. long traceCurTime2 = -1;
  905. String traceCurThread2 = null;
  906. for (String threadId: threads.keySet()) {
  907. ThreadInstance thread = threads.get(threadId);
  908. ArrayList<MethodExecution> roots = (ArrayList<MethodExecution>)thread.getRoot().clone();
  909. threadRoots.put(threadId, roots);
  910. TracePoint threadCurTp;
  911. do {
  912. MethodExecution threadCurExecution = roots.remove(0);
  913. threadCurTp = threadCurExecution.getEntryPoint();
  914. } while (!threadCurTp.isValid() && roots.size() > 0);
  915. if (threadCurTp.isValid()) {
  916. threadCurPoints.put(threadId, threadCurTp);
  917. long methodEntry = threadCurTp.getMethodExecution().getEntryTime();
  918. if (traceCurTime == -1 || traceCurTime > methodEntry) {
  919. traceCurTime2 = traceCurTime;
  920. traceCurThread2 = traceCurThread;
  921. traceCurTime = methodEntry;
  922. traceCurThread = threadId;
  923. } else if (traceCurTime2 == -1 || traceCurTime2 > methodEntry) {
  924. traceCurTime2 = methodEntry;
  925. traceCurThread2 = threadId;
  926. }
  927. } else {
  928. threadCurPoints.put(threadId, null);
  929. }
  930. }
  931. return traverseStatementsInTraceSub(visitor, threadRoots, threadCurPoints, traceCurThread, traceCurThread2, traceCurTime2);
  932. }
  933. private TracePoint traverseStatementsInTraceSub(IStatementVisitor visitor,
  934. HashMap<String, ArrayList<MethodExecution>> threadRoots,
  935. HashMap<String, TracePoint> threadCurPoints,
  936. String curThreadId, String nextThreadId, long nextThreadTime) {
  937. // 全スレッドの同期をとりながら順方向に実行文を探索する
  938. for (;;) {
  939. // 探索対象のスレッド内の順方向探索
  940. TracePoint curTp = threadCurPoints.get(curThreadId);
  941. while (curTp != null
  942. && (curTp.getStatement().getTimeStamp() <= nextThreadTime || nextThreadTime == -1)) {
  943. Statement statement = curTp.getStatement();
  944. if (!(visitor instanceof AbstractTracePointVisitor)) {
  945. if (visitor.preVisitStatement(statement)) return curTp;
  946. if (!(statement instanceof MethodInvocation)) {
  947. if (visitor.postVisitStatement(statement)) return curTp;
  948. }
  949. } else {
  950. // トレースポイントの情報も必要な場合
  951. if (((AbstractTracePointVisitor) visitor).preVisitStatement(statement, curTp)) return curTp;
  952. if (!(statement instanceof MethodInvocation)) {
  953. if (((AbstractTracePointVisitor) visitor).postVisitStatement(statement, curTp)) return curTp;
  954. }
  955. }
  956. curTp.stepNoReturn(); // 復帰せずに呼び出し木を潜っていく
  957. if (!curTp.isValid()) {
  958. // 復帰しないとこれ以上探索できない
  959. while (!curTp.stepOver()) { // 今度は復帰はするが潜らずに探索
  960. if (curTp.isValid()) {
  961. // 呼び出し先探索前に一度訪問済みのメソッド呼び出し行を、探索後もう一度訪問する
  962. if (!(visitor instanceof AbstractTracePointVisitor)) {
  963. if (visitor.postVisitStatement(curTp.getStatement())) return curTp;
  964. } else {
  965. // トレースポイントの情報も必要な場合
  966. if (((AbstractTracePointVisitor) visitor).postVisitStatement(curTp.getStatement(), curTp)) return curTp;
  967. }
  968. } else {
  969. // 呼び出し木の開始時点まで探索し終えた場合
  970. ArrayList<MethodExecution> roots = threadRoots.get(curThreadId);
  971. while (!curTp.isValid() && roots.size() > 0) {
  972. // 次の呼び出し木があればそれを最初から探索
  973. MethodExecution firstExecution = roots.remove(0);
  974. curTp = firstExecution.getEntryPoint();
  975. }
  976. if (curTp.isValid()) {
  977. // 次の呼び出し木があればそれを最初から探索
  978. threadCurPoints.put(curThreadId, curTp);
  979. } else {
  980. // そのスレッドの探索がすべて終了した場合
  981. threadCurPoints.put(curThreadId, null);
  982. curTp = null;
  983. }
  984. break;
  985. }
  986. }
  987. }
  988. }
  989. curThreadId = nextThreadId;
  990. if (curThreadId == null) break;
  991. // 次の次に探索すべきスレッド(未探索の領域が一番最初に始まるスレッド)を決定する
  992. nextThreadTime = -1;
  993. nextThreadId = null;
  994. boolean continueTraverse = false;
  995. for (String threadId: threadCurPoints.keySet()) {
  996. if (!threadId.equals(curThreadId)) {
  997. TracePoint threadTp = threadCurPoints.get(threadId);
  998. if (threadTp != null) {
  999. continueTraverse = true;
  1000. long threadTime = threadTp.getStatement().getTimeStamp();
  1001. if (threadTime > 0 && (nextThreadTime == -1 || nextThreadTime > threadTime)) {
  1002. nextThreadTime = threadTime;
  1003. nextThreadId = threadId;
  1004. }
  1005. }
  1006. }
  1007. }
  1008. if (!continueTraverse && threadCurPoints.get(curThreadId) == null) break;
  1009. }
  1010. return null;
  1011. }
  1012. /**
  1013. * トレース内の全スレッドを同期させならが全実行文を逆方向に探索する
  1014. *
  1015. * @param visitor 実行文のビジター
  1016. * @return 中断したトレースポイント
  1017. */
  1018. public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor) {
  1019. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  1020. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  1021. // 各スレッドにおいて一番最後に開始したメソッド実行を探す
  1022. long traceLastTime = 0;
  1023. String traceLastThread = null;
  1024. long traceLastTime2 = 0;
  1025. String traceLastThread2 = null;
  1026. for (String threadId: threads.keySet()) {
  1027. ThreadInstance thread = threads.get(threadId);
  1028. ArrayList<MethodExecution> root = (ArrayList<MethodExecution>)thread.getRoot().clone();
  1029. threadRoots.put(threadId, root);
  1030. TracePoint threadLastTp;
  1031. do {
  1032. MethodExecution threadLastExecution = root.remove(root.size() - 1);
  1033. threadLastTp = threadLastExecution.getExitPoint();
  1034. } while (!threadLastTp.isValid() && root.size() > 0);
  1035. if (threadLastTp.isValid()) {
  1036. threadLastPoints.put(threadId, threadLastTp);
  1037. if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, threadLastTp)) return threadLastTp;
  1038. long methodEntry = threadLastTp.getMethodExecution().getEntryTime();
  1039. if (traceLastTime < methodEntry) {
  1040. traceLastTime2 = traceLastTime;
  1041. traceLastThread2 = traceLastThread;
  1042. traceLastTime = methodEntry;
  1043. traceLastThread = threadId;
  1044. } else if (traceLastTime2 < methodEntry) {
  1045. traceLastTime2 = methodEntry;
  1046. traceLastThread2 = threadId;
  1047. }
  1048. } else {
  1049. threadLastPoints.put(threadId, null);
  1050. }
  1051. }
  1052. return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  1053. }
  1054. /**
  1055. *
  1056. * @param visitor
  1057. * @param before
  1058. * @return
  1059. */
  1060. public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor, TracePoint before) {
  1061. if (before == null) {
  1062. return traverseStatementsInTraceBackward(visitor);
  1063. }
  1064. if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, before)) return before;
  1065. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  1066. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  1067. String traceLastThread = null;
  1068. long traceLastTime2 = 0;
  1069. String traceLastThread2 = null;
  1070. ThreadInstance thread = threads.get(before.getStatement().getThreadNo());
  1071. for (String threadId: threads.keySet()) {
  1072. ThreadInstance t = threads.get(threadId);
  1073. ArrayList<MethodExecution> rootExecutions = (ArrayList<MethodExecution>)t.getRoot().clone();
  1074. threadRoots.put(threadId, rootExecutions);
  1075. if (t == thread) {
  1076. traceLastThread = threadId;
  1077. threadLastPoints.put(threadId, before);
  1078. for (int n = rootExecutions.size() - 1; n >= 0; n--) {
  1079. MethodExecution root = rootExecutions.get(n);
  1080. if (root.getEntryTime() > before.getMethodExecution().getEntryTime()) {
  1081. rootExecutions.remove(n);
  1082. } else {
  1083. break;
  1084. }
  1085. }
  1086. if (rootExecutions.size() > 0) {
  1087. rootExecutions.remove(rootExecutions.size() - 1);
  1088. }
  1089. } else {
  1090. MethodExecution threadLastExecution = rootExecutions.remove(rootExecutions.size() - 1);
  1091. TracePoint threadBeforeTp = getLastMethodEntryInThread(rootExecutions, threadLastExecution.getExitOutPoint(), before.getMethodExecution().getEntryTime());
  1092. threadLastPoints.put(threadId, threadBeforeTp);
  1093. if (threadBeforeTp != null) {
  1094. long threadLastTime = threadBeforeTp.getMethodExecution().getEntryTime();
  1095. if (traceLastTime2 < threadLastTime) {
  1096. traceLastTime2 = threadLastTime;
  1097. traceLastThread2 = threadId;
  1098. }
  1099. }
  1100. }
  1101. }
  1102. return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  1103. }
  1104.  
  1105. private TracePoint traverseStatementsInTraceBackwardSub(IStatementVisitor visitor,
  1106. HashMap<String, ArrayList<MethodExecution>> threadRoots,
  1107. HashMap<String, TracePoint> threadLastPoints,
  1108. String traceLastThread, String traceLastThread2, long traceLastTime2) {
  1109. // 全スレッドの同期をとりながら逆向きに実行文を探索する
  1110. for (;;) {
  1111. // 探索対象のスレッド内の逆向き探索
  1112. TracePoint lastTp = threadLastPoints.get(traceLastThread);
  1113. do {
  1114. if (lastTp.stepBackOver()) {
  1115. // そのスレッドの次のメソッド実行開始時点まで探索する
  1116. if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, lastTp)) return lastTp;
  1117. } else {
  1118. // 呼び出し元に戻った場合
  1119. if (lastTp.isValid()) {
  1120. if (visitor.postVisitStatement(lastTp.getStatement())) return lastTp;
  1121. } else {
  1122. // 呼び出し木の開始時点まで探索し終えた場合
  1123. ArrayList<MethodExecution> root = threadRoots.get(traceLastThread);
  1124. while (!lastTp.isValid() && root.size() > 0) {
  1125. // 次の呼び出し木があればそれを最後から探索
  1126. MethodExecution lastExecution = root.remove(root.size() - 1);
  1127. lastTp = lastExecution.getExitPoint();
  1128. }
  1129. if (lastTp.isValid()) {
  1130. // 次の呼び出し木があればそれを最後から探索
  1131. threadLastPoints.put(traceLastThread, lastTp);
  1132. if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, lastTp)) return lastTp;
  1133. } else {
  1134. // そのスレッドの探索がすべて終了した場合
  1135. threadLastPoints.put(traceLastThread, null);
  1136. break;
  1137. }
  1138. }
  1139. }
  1140. } while (lastTp.getMethodExecution().getEntryTime() >= traceLastTime2);
  1141. traceLastThread = traceLastThread2;
  1142. // 次の次に探索すべきスレッド(未探索の領域が一番最後まで残っているスレッド)を決定する
  1143. traceLastTime2 = 0;
  1144. traceLastThread2 = null;
  1145. boolean continueTraverse = false;
  1146. for (String threadId: threadLastPoints.keySet()) {
  1147. if (!threadId.equals(traceLastThread)) {
  1148. TracePoint threadLastTp = threadLastPoints.get(threadId);
  1149. if (threadLastTp != null) {
  1150. continueTraverse = true;
  1151. long threadLastTime = threadLastTp.getMethodExecution().getEntryTime();
  1152. if (traceLastTime2 < threadLastTime) {
  1153. traceLastTime2 = threadLastTime;
  1154. traceLastThread2 = threadId;
  1155. }
  1156. }
  1157. }
  1158. }
  1159. if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break;
  1160. }
  1161. return null;
  1162. }
  1163. /**
  1164. * before で指定したトレースポイント以前の同一呼び出し木内の全実行文を逆向きに探索する(ただし、visitor が true を返すまで)
  1165. * @param visitor ビジター
  1166. * @param before 探索の開始点(探索対象スレッドも指定している)
  1167. * @return true -- 探索を中断した, false -- 最後まで探索した
  1168. */
  1169. public boolean traverseStatementsInCallTreeBackward(IStatementVisitor visitor, TracePoint before) {
  1170. for (;;) {
  1171. if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, before)) return true;
  1172. while (!before.stepBackOver()) {
  1173. if (!before.isValid()) break;
  1174. if (visitor.postVisitStatement(before.getStatement())) return true;
  1175. }
  1176. if (!before.isValid()) break;
  1177. }
  1178. return false;
  1179. }
  1180.  
  1181. /**
  1182. * before以前の呼び出し木を呼び出し先からの復帰をせずに行けるところまで逆向きに探索する
  1183. *
  1184. * @param visitor 実行文のビジター
  1185. * @param before 探索開始実行時点
  1186. * @return true -- 探索を中断した, false -- 復帰をしない限りこれ以上進めない
  1187. */
  1188. private boolean traverseStatamentsInCallTreeBackwardNoReturn(IStatementVisitor visitor, TracePoint before) {
  1189. for (;;) {
  1190. Statement statement = before.getStatement();
  1191. if (statement instanceof MethodInvocation) {
  1192. // メソッド呼び出し文の場合は、呼び出しの前後で preVisit と postVisit を別々に実行する
  1193. if (visitor.preVisitStatement(statement)) return true;
  1194. before.stepBackNoReturn();
  1195. if (!before.isValid()) {
  1196. // 呼び出し先のメソッドで実行文が記録されていない場合
  1197. before.stepBackOver();
  1198. if (visitor.postVisitStatement(statement)) return true;
  1199. if (before.isMethodEntry()) return false;
  1200. before.stepBackOver();
  1201. }
  1202. } else {
  1203. if (visitor.preVisitStatement(statement)) return true;
  1204. if (visitor.postVisitStatement(statement)) return true;
  1205. if (before.isMethodEntry()) return false;
  1206. before.stepBackNoReturn();
  1207. }
  1208. }
  1209. }
  1210. /**
  1211. * before で指定したトレースポイント以前の同一スレッド内の全メソッド実行を呼び出し木の中で逆向きに探索する(ただし、visitor が true を返すまで)
  1212. * @param visitor ビジター
  1213. * @param before 探索の開始点(探索対象スレッドも指定している)
  1214. * @return true -- 探索を中断した, false -- 最後まで探索した
  1215. */
  1216. public boolean traverseMethodExecutionsInCallTreeBackward(IMethodExecutionVisitor visitor, TracePoint before) {
  1217. ArrayList<MethodExecution> prevMethodExecutions = before.getPreviouslyCalledMethods();
  1218. for (int i = prevMethodExecutions.size() - 1; i >= 0; i--) {
  1219. MethodExecution child = prevMethodExecutions.get(i);
  1220. if (child.traverseMethodExecutionsBackward(visitor)) return true;
  1221. }
  1222. MethodExecution methodExecution = before.getMethodExecution();
  1223. if (visitor.postVisitMethodExecution(methodExecution, null)) return true;
  1224. TracePoint caller = methodExecution.getCallerTracePoint();
  1225. if (caller != null) {
  1226. if (traverseMethodExecutionsInCallTreeBackward(visitor, caller)) return true;
  1227. }
  1228. return false;
  1229. }
  1230.  
  1231. public static String getDeclaringType(String methodSignature, boolean isConstructor) {
  1232. if (methodSignature == null) return null;
  1233. if (isConstructor) {
  1234. String[] fragments = methodSignature.split("\\(");
  1235. return fragments[0].substring(fragments[0].lastIndexOf(' ') + 1);
  1236. }
  1237. String[] fragments = methodSignature.split("\\(");
  1238. return fragments[0].substring(fragments[0].lastIndexOf(' ') + 1, fragments[0].lastIndexOf('.'));
  1239. }
  1240. public static String getMethodName(String methodSignature) {
  1241. String[] fragments = methodSignature.split("\\(");
  1242. String[] fragments2 = fragments[0].split("\\.");
  1243. return fragments2[fragments2.length - 1];
  1244. }
  1245. public static String getReturnType(String methodSignature) {
  1246. String[] fragments = methodSignature.split(" ");
  1247. for (int i = 0; i < fragments.length; i++) {
  1248. if (!fragments[i].equals("public") && !fragments[i].equals("private") && !fragments[i].equals("protected")
  1249. && !fragments[i].equals("abstract") && !fragments[i].equals("final") && !fragments[i].equals("static")
  1250. && !fragments[i].equals("synchronized") && !fragments[i].equals("native")) {
  1251. return fragments[i];
  1252. }
  1253. }
  1254. return "";
  1255. }
  1256. public static boolean isNull(String objectId) {
  1257. return objectId.equals("0");
  1258. }
  1259. public static String getNull() {
  1260. return "0";
  1261. }
  1262.  
  1263. public static boolean isPrimitive(String typeName) {
  1264. if (typeName.equals("int")
  1265. || typeName.equals("boolean")
  1266. || typeName.equals("long")
  1267. || typeName.equals("double")
  1268. || typeName.equals("float")
  1269. || typeName.equals("char")
  1270. || typeName.equals("byte")
  1271. || typeName.equals("java.lang.Integer")
  1272. || typeName.equals("java.lang.Boolean")
  1273. || typeName.equals("java.lang.Long")
  1274. || typeName.equals("java.lang.Double")
  1275. || typeName.equals("java.lang.Float")
  1276. || typeName.equals("java.lang.Character")
  1277. || typeName.equals("java.lang.Byte")) return true;
  1278. return false;
  1279. }
  1280. }