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