1 /* 2 * Copyright (c) 2010, 2013, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.ir; 27 28 import jdk.nashorn.internal.codegen.types.Type; 29 30 /** 31 * Class describing one or more local variable conversions that needs to be performed on entry to a control flow join 32 * point. Note that the class is named as a singular "Conversion" and not a plural "Conversions", but instances of the 33 * class have a reference to the next conversion, so multiple conversions are always represented with a single instance 34 * that is a head of a linked list of instances. 35 * @see JoinPredecessor 36 */ 37 public final class LocalVariableConversion { 38 private final Symbol symbol; 39 // TODO: maybe introduce a type pair class? These will often be repeated. 40 private final Type from; 41 private final Type to; 42 private final LocalVariableConversion next; 43 44 /** 45 * Creates a new object representing a local variable conversion. 46 * @param symbol the symbol representing the local variable whose value is being converted. 47 * @param from the type value is being converted from. 48 * @param to the type value is being converted to. 49 * @param next next conversion at the same join point, if any (the conversion object implements a singly-linked 50 * list of conversions). 51 */ 52 public LocalVariableConversion(final Symbol symbol, final Type from, final Type to, final LocalVariableConversion next) { 53 this.symbol = symbol; 54 this.from = from; 55 this.to = to; 56 this.next = next; 57 } 58 59 /** 60 * Returns the type being converted from. 61 * @return the type being converted from. 62 */ 63 public Type getFrom() { 64 return from; 65 } 66 67 /** 68 * Returns the type being converted to. 69 * @return the type being converted to. 70 */ 71 public Type getTo() { 72 return to; 73 } 74 75 /** 76 * Returns the next conversion at the same join point, or null if this is the last one. 77 * @return the next conversion at the same join point. 78 */ 79 public LocalVariableConversion getNext() { 80 return next; 81 } 82 83 /** 84 * Returns the symbol representing the local variable whose value is being converted. 85 * @return the symbol representing the local variable whose value is being converted. 86 */ 87 public Symbol getSymbol() { 88 return symbol; 89 } 90 91 /** 92 * Returns true if this conversion is live. A conversion is live if the symbol has a slot for the conversion's 93 * {@link #getTo() to} type. If a conversion is dead, it can be omitted in code generator. 94 * @return true if this conversion is live. 95 */ 96 public boolean isLive() { 97 return symbol.hasSlotFor(to); 98 } 99 100 /** 101 * Returns true if this conversion {@link #isLive()}, or if any of its {@link #getNext()} conversions are live. 102 * @return true if this conversion, or any conversion following it, are live. 103 */ 104 public boolean isAnyLive() { 105 return isLive() || isAnyLive(next); 106 } 107 108 /** 109 * Returns true if the passed join predecessor has {@link #isAnyLive()} conversion. 110 * @param jp the join predecessor being examined. 111 * @return true if the join predecessor conversion is not null and {@link #isAnyLive()}. 112 */ 113 public static boolean hasLiveConversion(final JoinPredecessor jp) { 114 return isAnyLive(jp.getLocalVariableConversion()); 115 } 116 117 /** 118 * Returns true if the passed conversion is not null, and it {@link #isAnyLive()}. 119 * @parameter conv the conversion being tested for liveness. 120 * @return true if the conversion is not null and {@link #isAnyLive()}. 121 */ 122 private static boolean isAnyLive(final LocalVariableConversion conv) { 123 return conv != null && conv.isAnyLive(); 124 } 125 126 @Override 127 public String toString() { 128 return toString(new StringBuilder()).toString(); 129 } 130 131 /** 132 * Generates a string representation of this conversion in the passed string builder. 133 * @param sb the string builder in which to generate a string representation of this conversion. 134 * @return the passed in string builder. 135 */ 136 public StringBuilder toString(final StringBuilder sb) { 137 if(isLive()) { 138 return toStringNext(sb.append('\u27e6'), true).append("\u27e7 "); 139 } 140 return next == null ? sb : next.toString(sb); 141 } 142 143 /** 144 * Generates a string representation of the passed conversion in the passed string builder. 145 * @param conv the conversion to render in the string builder. 146 * @param sb the string builder in which to generate a string representation of this conversion. 147 * @return the passed in string builder. 148 */ 149 public static StringBuilder toString(final LocalVariableConversion conv, final StringBuilder sb) { 150 return conv == null ? sb : conv.toString(sb); 151 } 152 153 private StringBuilder toStringNext(final StringBuilder sb, final boolean first) { 154 if(isLive()) { 155 if(!first) { 156 sb.append(", "); 157 } 158 sb.append(symbol.getName()).append(':').append(getTypeChar(from)).append('\u2192').append(getTypeChar(to)); 159 return next == null ? sb : next.toStringNext(sb, false); 160 } 161 return next == null ? sb : next.toStringNext(sb, first); 162 } 163 164 private static char getTypeChar(final Type type) { 165 if(type == Type.UNDEFINED) { 166 return 'U'; 167 } else if(type.isObject()) { 168 return 'O'; 169 } else if(type == Type.BOOLEAN) { 170 return 'Z'; 171 } 172 return type.getBytecodeStackType(); 173 } 174 }