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    }