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    }