1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package vm.mlvm.meth.share.transform.v2; 25 26 import java.io.*; 27 import java.util.*; 28 29 import vm.mlvm.share.Env; 30 31 import nsk.share.test.TestUtils; 32 33 34 public class MHMacroTF extends MHTF { 35 36 private final String name; 37 private final Collection<MHCall> calls = new HashSet<>(); 38 private final Collection<MHCall> outboundCalls = new LinkedHashSet<>(); 39 private MHCall inboundCall = null; 40 private final Collection<MHTF> tfs = new LinkedHashSet<>(); 41 MHMacroTF(String name)42 public MHMacroTF(String name) { 43 this.name = name; 44 } 45 addNewInboundCall(MHCall call)46 private void addNewInboundCall(MHCall call) { 47 TestUtils.assertNotInCollection(this.calls, call); 48 49 this.inboundCall = call; 50 this.calls.add(call); 51 } 52 addOutboundCall(MHCall call)53 public void addOutboundCall(MHCall call) { 54 TestUtils.assertNotInCollection(this.calls, call); 55 56 this.calls.add(call); 57 this.outboundCalls.add(call); 58 } 59 addTransformation(MHTF tf)60 public MHCall addTransformation(MHTF tf) throws IllegalArgumentException, 61 NoSuchMethodException, IllegalAccessException { 62 TestUtils.assertNotInCollection(this.tfs, tf); 63 for (MHCall c : tf.getOutboundCalls()) { 64 TestUtils.assertInCollection(this.calls, c); 65 } 66 67 Env.traceDebug("MHMacroTF: adding %s", tf); 68 69 this.tfs.add(tf); 70 MHCall inboundCall = tf.computeInboundCall(); 71 addNewInboundCall(inboundCall); 72 73 Env.traceDebug("MHMacroTF: current inbound call: %s", inboundCall); 74 75 return inboundCall; 76 } 77 78 @Override computeInboundCall()79 public MHCall computeInboundCall() { 80 return inboundCall; 81 } 82 83 @Override getOutboundCalls()84 public MHCall[] getOutboundCalls() { 85 return this.outboundCalls.toArray(new MHCall[0]); 86 } 87 88 @Override getSubTFs()89 public MHTF[] getSubTFs() { 90 return this.tfs.toArray(new MHTF[0]); 91 } 92 93 @Override getName()94 protected String getName() { 95 return name + " graph"; 96 } 97 98 @Override getDescription()99 protected String getDescription() { 100 StringBuilder result = new StringBuilder("\n"); 101 Deque<PrettyPrintElement> printElements = new ArrayDeque<>(); 102 printElements.add(new PrettyPrintElement("", " ", inboundCall, true)); 103 PrettyPrintElement current; 104 while (!printElements.isEmpty()) { 105 current = printElements.pop(); 106 appendElement(result, printElements, current.topCallPrefix, 107 current.subCallPrefix, current.topCall, 108 current.isRecursive); 109 } 110 String filename = getName() + "-" 111 + Long.toString(System.currentTimeMillis(), Character.MAX_RADIX) 112 + ".txt"; 113 try (Writer writer = new FileWriter(filename)) { 114 writer.write(result.toString()); 115 } catch (IOException e) { 116 return result.toString(); 117 } 118 return "see " + filename; 119 } 120 appendElement(StringBuilder result, Deque<PrettyPrintElement> deque, String topCallPrefix, String subCallPrefix, MHCall topCall, boolean isRecursive)121 private void appendElement(StringBuilder result, 122 Deque<PrettyPrintElement> deque, String topCallPrefix, 123 String subCallPrefix, MHCall topCall, boolean isRecursive) { 124 MHCall[] outCalls = topCall.getTarget().getOutboundCalls(); 125 boolean printSubTree = (isRecursive && outCalls.length > 0); 126 result.append(topCall.prettyPrint(topCallPrefix + "->", 127 subCallPrefix + (printSubTree ? "|" : " ") + " ") + "\n"); 128 if (printSubTree) { 129 for (int n = outCalls.length - 1, i = n; i >= 0; --i) { 130 MHCall outCall = outCalls[i]; 131 boolean isLastSubtree = (i == n); 132 String curTopCallPrefix = subCallPrefix 133 + (isLastSubtree ? "\\" : "|") 134 + "--"; 135 String curSubCallPrefix = subCallPrefix 136 + (isLastSubtree ? " " : "|") 137 + " "; 138 deque.addFirst(new PrettyPrintElement(curTopCallPrefix, 139 curSubCallPrefix, outCall, 140 !outboundCalls.contains(outCall))); 141 } 142 } 143 } 144 145 146 private static class PrettyPrintElement { 147 final String topCallPrefix; 148 final String subCallPrefix; 149 final MHCall topCall; 150 final boolean isRecursive; 151 PrettyPrintElement(String topCallPrefix, String subCallPrefix, MHCall topCall, boolean isRecursive)152 private PrettyPrintElement(String topCallPrefix, 153 String subCallPrefix, MHCall topCall, boolean isRecursive) { 154 this.topCallPrefix = topCallPrefix; 155 this.subCallPrefix = subCallPrefix; 156 this.topCall = topCall; 157 this.isRecursive = isRecursive; 158 } 159 } 160 161 } 162