001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.codegen.optimization.common;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.org.objectweb.asm.Handle;
022 import org.jetbrains.org.objectweb.asm.Opcodes;
023 import org.jetbrains.org.objectweb.asm.Type;
024 import org.jetbrains.org.objectweb.asm.tree.*;
025 import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
026 import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
027 import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter;
028
029 import java.util.List;
030
031 import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
032
033 public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
034 private final boolean tolerantToUninitializedValues;
035
036 public OptimizationBasicInterpreter(boolean tolerantToUninitializedValues) {
037 super(ASM5);
038 this.tolerantToUninitializedValues = tolerantToUninitializedValues;
039 }
040
041 public OptimizationBasicInterpreter() {
042 this(false);
043 }
044
045 @Override
046 @Nullable
047 public StrictBasicValue newValue(@Nullable Type type) {
048 if (type == null) {
049 return UNINITIALIZED_VALUE;
050 }
051
052 switch (type.getSort()) {
053 case Type.VOID:
054 return null;
055 case Type.INT:
056 return INT_VALUE;
057 case Type.FLOAT:
058 return FLOAT_VALUE;
059 case Type.LONG:
060 return LONG_VALUE;
061 case Type.DOUBLE:
062 return DOUBLE_VALUE;
063 case Type.BOOLEAN:
064 return BOOLEAN_VALUE;
065 case Type.CHAR:
066 return CHAR_VALUE;
067 case Type.BYTE:
068 return BYTE_VALUE;
069 case Type.SHORT:
070 return SHORT_VALUE;
071 case Type.OBJECT:
072 return new StrictBasicValue(type);
073 case Type.ARRAY:
074 return StrictBasicValue.REFERENCE_VALUE;
075 default:
076 throw new IllegalArgumentException("Unknown type sort " + type.getSort());
077 }
078 }
079
080 @Override
081 public BasicValue newOperation(@NotNull AbstractInsnNode insn) throws AnalyzerException {
082 switch (insn.getOpcode()) {
083 case ACONST_NULL:
084 return newValue(Type.getObjectType("null"));
085 case ICONST_M1:
086 case ICONST_0:
087 case ICONST_1:
088 case ICONST_2:
089 case ICONST_3:
090 case ICONST_4:
091 case ICONST_5:
092 return StrictBasicValue.INT_VALUE;
093 case LCONST_0:
094 case LCONST_1:
095 return StrictBasicValue.LONG_VALUE;
096 case FCONST_0:
097 case FCONST_1:
098 case FCONST_2:
099 return StrictBasicValue.FLOAT_VALUE;
100 case DCONST_0:
101 case DCONST_1:
102 return StrictBasicValue.DOUBLE_VALUE;
103 case BIPUSH:
104 case SIPUSH:
105 return StrictBasicValue.INT_VALUE;
106 case LDC:
107 Object cst = ((LdcInsnNode) insn).cst;
108 if (cst instanceof Integer) {
109 return StrictBasicValue.INT_VALUE;
110 }
111 else if (cst instanceof Float) {
112 return StrictBasicValue.FLOAT_VALUE;
113 }
114 else if (cst instanceof Long) {
115 return StrictBasicValue.LONG_VALUE;
116 }
117 else if (cst instanceof Double) {
118 return StrictBasicValue.DOUBLE_VALUE;
119 }
120 else if (cst instanceof String) {
121 return newValue(Type.getObjectType("java/lang/String"));
122 }
123 else if (cst instanceof Type) {
124 int sort = ((Type) cst).getSort();
125 if (sort == Type.OBJECT || sort == Type.ARRAY) {
126 return newValue(Type.getObjectType("java/lang/Class"));
127 }
128 else if (sort == Type.METHOD) {
129 return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
130 }
131 else {
132 throw new IllegalArgumentException("Illegal LDC constant " + cst);
133 }
134 }
135 else if (cst instanceof Handle) {
136 return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
137 }
138 else {
139 throw new IllegalArgumentException("Illegal LDC constant " + cst);
140 }
141 case GETSTATIC:
142 return newValue(Type.getType(((FieldInsnNode) insn).desc));
143 case NEW:
144 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
145 default:
146 throw new Error("Internal error.");
147 }
148 }
149
150 @Override
151 public BasicValue copyOperation(@NotNull AbstractInsnNode insn, BasicValue value) throws AnalyzerException {
152 return value;
153 }
154
155 @Override
156 public BasicValue binaryOperation(
157 @NotNull AbstractInsnNode insn,
158 @NotNull BasicValue value1,
159 @NotNull BasicValue value2
160 ) throws AnalyzerException {
161 switch (insn.getOpcode()) {
162 case IALOAD:
163 case BALOAD:
164 case CALOAD:
165 case SALOAD:
166 case IADD:
167 case ISUB:
168 case IMUL:
169 case IDIV:
170 case IREM:
171 case ISHL:
172 case ISHR:
173 case IUSHR:
174 case IAND:
175 case IOR:
176 case IXOR:
177 return StrictBasicValue.INT_VALUE;
178 case FALOAD:
179 case FADD:
180 case FSUB:
181 case FMUL:
182 case FDIV:
183 case FREM:
184 return StrictBasicValue.FLOAT_VALUE;
185 case LALOAD:
186 case LADD:
187 case LSUB:
188 case LMUL:
189 case LDIV:
190 case LREM:
191 case LSHL:
192 case LSHR:
193 case LUSHR:
194 case LAND:
195 case LOR:
196 case LXOR:
197 return StrictBasicValue.LONG_VALUE;
198 case DALOAD:
199 case DADD:
200 case DSUB:
201 case DMUL:
202 case DDIV:
203 case DREM:
204 return StrictBasicValue.DOUBLE_VALUE;
205 case AALOAD:
206 return StrictBasicValue.REFERENCE_VALUE;
207 case LCMP:
208 case FCMPL:
209 case FCMPG:
210 case DCMPL:
211 case DCMPG:
212 return StrictBasicValue.INT_VALUE;
213 case IF_ICMPEQ:
214 case IF_ICMPNE:
215 case IF_ICMPLT:
216 case IF_ICMPGE:
217 case IF_ICMPGT:
218 case IF_ICMPLE:
219 case IF_ACMPEQ:
220 case IF_ACMPNE:
221 case PUTFIELD:
222 return null;
223 default:
224 throw new Error("Internal error.");
225 }
226 }
227
228 @Override
229 public BasicValue ternaryOperation(
230 AbstractInsnNode insn, BasicValue value1, BasicValue value2, BasicValue value3
231 ) throws AnalyzerException {
232 return null;
233 }
234
235 @Override
236 public BasicValue naryOperation(
237 AbstractInsnNode insn, List<? extends BasicValue> values
238 ) throws AnalyzerException {
239 int opcode = insn.getOpcode();
240 if (opcode == MULTIANEWARRAY) {
241 return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
242 }
243 else if (opcode == INVOKEDYNAMIC) {
244 return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc));
245 }
246 else {
247 return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
248 }
249 }
250
251 @Override
252 public void returnOperation(
253 AbstractInsnNode insn, BasicValue value, BasicValue expected
254 ) throws AnalyzerException {
255 }
256
257 @Override
258 public BasicValue unaryOperation(
259 AbstractInsnNode insn,
260 BasicValue value
261 ) throws AnalyzerException {
262 switch (insn.getOpcode()) {
263 case INEG:
264 case IINC:
265 case L2I:
266 case F2I:
267 case D2I:
268 case I2B:
269 case I2C:
270 case I2S:
271 return StrictBasicValue.INT_VALUE;
272 case FNEG:
273 case I2F:
274 case L2F:
275 case D2F:
276 return StrictBasicValue.FLOAT_VALUE;
277 case LNEG:
278 case I2L:
279 case F2L:
280 case D2L:
281 return StrictBasicValue.LONG_VALUE;
282 case DNEG:
283 case I2D:
284 case L2D:
285 case F2D:
286 return StrictBasicValue.DOUBLE_VALUE;
287 case IFEQ:
288 case IFNE:
289 case IFLT:
290 case IFGE:
291 case IFGT:
292 case IFLE:
293 case TABLESWITCH:
294 case LOOKUPSWITCH:
295 case IRETURN:
296 case LRETURN:
297 case FRETURN:
298 case DRETURN:
299 case ARETURN:
300 case PUTSTATIC:
301 return null;
302 case GETFIELD:
303 return newValue(Type.getType(((FieldInsnNode) insn).desc));
304 case NEWARRAY:
305 switch (((IntInsnNode) insn).operand) {
306 case T_BOOLEAN:
307 return newValue(Type.getType("[Z"));
308 case T_CHAR:
309 return newValue(Type.getType("[C"));
310 case T_BYTE:
311 return newValue(Type.getType("[B"));
312 case T_SHORT:
313 return newValue(Type.getType("[S"));
314 case T_INT:
315 return newValue(Type.getType("[I"));
316 case T_FLOAT:
317 return newValue(Type.getType("[F"));
318 case T_DOUBLE:
319 return newValue(Type.getType("[D"));
320 case T_LONG:
321 return newValue(Type.getType("[J"));
322 default:
323 throw new AnalyzerException(insn, "Invalid array type");
324 }
325 case ANEWARRAY:
326 String desc = ((TypeInsnNode) insn).desc;
327 return newValue(Type.getType("[" + Type.getObjectType(desc)));
328 case ARRAYLENGTH:
329 return StrictBasicValue.INT_VALUE;
330 case ATHROW:
331 return null;
332 case CHECKCAST:
333 desc = ((TypeInsnNode) insn).desc;
334 return newValue(Type.getObjectType(desc));
335 case INSTANCEOF:
336 return StrictBasicValue.INT_VALUE;
337 case MONITORENTER:
338 case MONITOREXIT:
339 case IFNULL:
340 case IFNONNULL:
341 return null;
342 default:
343 throw new Error("Internal error.");
344 }
345 }
346
347 @NotNull
348 @Override
349 public BasicValue merge(
350 @NotNull BasicValue v, @NotNull BasicValue w
351 ) {
352 if (v.equals(w)) return v;
353
354 if (tolerantToUninitializedValues) {
355 if (v == StrictBasicValue.UNINITIALIZED_VALUE) return w;
356 if (w == StrictBasicValue.UNINITIALIZED_VALUE) return v;
357 }
358 else if (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
359 return StrictBasicValue.UNINITIALIZED_VALUE;
360 }
361
362 // if merge of two references then `lub` is java/lang/Object
363 // arrays also are BasicValues with reference type's
364 if (v.getType().getSort() == Type.OBJECT && w.getType().getSort() == Type.OBJECT) {
365 return StrictBasicValue.REFERENCE_VALUE;
366 }
367
368 assert v.getType().getSort() != Type.ARRAY && w.getType().getSort() != Type.ARRAY : "There should not be arrays";
369
370
371 // if merge of something can be stored in int var (int, char, boolean, byte, character)
372 if (v.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE &&
373 w.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE) {
374 return StrictBasicValue.INT_VALUE;
375 }
376
377 return StrictBasicValue.UNINITIALIZED_VALUE;
378 }
379 }