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.kotlin.codegen.AsmUtil;
022 import org.jetbrains.org.objectweb.asm.Handle;
023 import org.jetbrains.org.objectweb.asm.Opcodes;
024 import org.jetbrains.org.objectweb.asm.Type;
025 import org.jetbrains.org.objectweb.asm.tree.*;
026 import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
027 import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
028 import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter;
029
030 import java.util.List;
031
032 import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
033
034 public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
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 case Type.ARRAY:
067 return new StrictBasicValue(type);
068 default:
069 throw new IllegalArgumentException("Unknown type sort " + type.getSort());
070 }
071 }
072
073 @Override
074 public BasicValue newOperation(@NotNull AbstractInsnNode insn) throws AnalyzerException {
075 switch (insn.getOpcode()) {
076 case ACONST_NULL:
077 return NULL_VALUE;
078 case ICONST_M1:
079 case ICONST_0:
080 case ICONST_1:
081 case ICONST_2:
082 case ICONST_3:
083 case ICONST_4:
084 case ICONST_5:
085 return StrictBasicValue.INT_VALUE;
086 case LCONST_0:
087 case LCONST_1:
088 return StrictBasicValue.LONG_VALUE;
089 case FCONST_0:
090 case FCONST_1:
091 case FCONST_2:
092 return StrictBasicValue.FLOAT_VALUE;
093 case DCONST_0:
094 case DCONST_1:
095 return StrictBasicValue.DOUBLE_VALUE;
096 case BIPUSH:
097 case SIPUSH:
098 return StrictBasicValue.INT_VALUE;
099 case LDC:
100 Object cst = ((LdcInsnNode) insn).cst;
101 if (cst instanceof Integer) {
102 return StrictBasicValue.INT_VALUE;
103 }
104 else if (cst instanceof Float) {
105 return StrictBasicValue.FLOAT_VALUE;
106 }
107 else if (cst instanceof Long) {
108 return StrictBasicValue.LONG_VALUE;
109 }
110 else if (cst instanceof Double) {
111 return StrictBasicValue.DOUBLE_VALUE;
112 }
113 else if (cst instanceof String) {
114 return newValue(Type.getObjectType("java/lang/String"));
115 }
116 else if (cst instanceof Type) {
117 int sort = ((Type) cst).getSort();
118 if (sort == Type.OBJECT || sort == Type.ARRAY) {
119 return newValue(Type.getObjectType("java/lang/Class"));
120 }
121 else if (sort == Type.METHOD) {
122 return newValue(Type.getObjectType("java/lang/invoke/MethodType"));
123 }
124 else {
125 throw new IllegalArgumentException("Illegal LDC constant " + cst);
126 }
127 }
128 else if (cst instanceof Handle) {
129 return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
130 }
131 else {
132 throw new IllegalArgumentException("Illegal LDC constant " + cst);
133 }
134 case GETSTATIC:
135 return newValue(Type.getType(((FieldInsnNode) insn).desc));
136 case NEW:
137 return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
138 default:
139 throw new Error("Internal error.");
140 }
141 }
142
143 @Override
144 public BasicValue copyOperation(@NotNull AbstractInsnNode insn, BasicValue value) throws AnalyzerException {
145 return value;
146 }
147
148 @Override
149 public BasicValue binaryOperation(
150 @NotNull AbstractInsnNode insn,
151 @NotNull BasicValue value1,
152 @NotNull BasicValue value2
153 ) throws AnalyzerException {
154 if (insn.getOpcode() == Opcodes.AALOAD) {
155 Type arrayType = value1.getType();
156 if (arrayType != null && arrayType.getSort() == Type.ARRAY) {
157 return new StrictBasicValue(AsmUtil.correctElementType(arrayType));
158 }
159 }
160
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 (v == StrictBasicValue.UNINITIALIZED_VALUE || w == StrictBasicValue.UNINITIALIZED_VALUE) {
355 return StrictBasicValue.UNINITIALIZED_VALUE;
356 }
357
358 // if merge of two references then `lub` is java/lang/Object
359 // arrays also are BasicValues with reference type's
360 if (isReference(v) && isReference(w)) {
361 if (v == NULL_VALUE) return newValue(w.getType());
362 if (w == NULL_VALUE) return newValue(v.getType());
363
364 return StrictBasicValue.REFERENCE_VALUE;
365 }
366
367 // if merge of something can be stored in int var (int, char, boolean, byte, character)
368 if (v.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE &&
369 w.getType().getOpcode(Opcodes.ISTORE) == Opcodes.ISTORE) {
370 return StrictBasicValue.INT_VALUE;
371 }
372
373 return StrictBasicValue.UNINITIALIZED_VALUE;
374 }
375
376 private static boolean isReference(@NotNull BasicValue v) {
377 return v.getType().getSort() == Type.OBJECT || v.getType().getSort() == Type.ARRAY;
378 }
379 }