1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package lockedregioncodeinjection;
15 
16 import org.objectweb.asm.Type;
17 import org.objectweb.asm.tree.AbstractInsnNode;
18 import org.objectweb.asm.tree.MethodInsnNode;
19 import org.objectweb.asm.tree.analysis.AnalyzerException;
20 import org.objectweb.asm.tree.analysis.BasicInterpreter;
21 import org.objectweb.asm.tree.analysis.BasicValue;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 /**
27  * A simple dataflow analysis to determine if the operands on the stack must be one of target lock
28  * class type.
29  */
30 public class LockTargetStateAnalysis extends BasicInterpreter {
31 
32     private final List<LockTarget> targetLocks;
33 
LockTargetStateAnalysis(List<LockTarget> targetLocks)34     public LockTargetStateAnalysis(List<LockTarget> targetLocks) {
35         super(Utils.ASM_VERSION);
36         this.targetLocks = targetLocks;
37     }
38 
39     @Override
naryOperation(AbstractInsnNode inst, @SuppressWarnings("rawtypes") List args)40     public BasicValue naryOperation(AbstractInsnNode inst, @SuppressWarnings("rawtypes") List args)
41             throws AnalyzerException {
42         // We target the return type of any invocation.
43 
44         @SuppressWarnings("unchecked")
45         BasicValue base = super.naryOperation(inst, args);
46         if (!(inst instanceof MethodInsnNode)) {
47             return base;
48         }
49 
50         MethodInsnNode invoke = (MethodInsnNode) inst;
51         Type returnType = Type.getReturnType(invoke.desc);
52         if (returnType.equals(Type.VOID_TYPE)) {
53             return base;
54         }
55 
56         List<LockTarget> types = new ArrayList<>();
57 
58         for (LockTarget target : targetLocks) {
59             if (returnType.getDescriptor().equals(target.getTargetDesc())) {
60                 types.add(target);
61             }
62         }
63 
64         return new LockTargetState(base.getType(), types);
65     }
66 
67     @Override
newValue(Type type)68     public BasicValue newValue(Type type) {
69         BasicValue base = super.newValue(type);
70         List<LockTarget> types = new ArrayList<>();
71 
72         if (type == null) {
73             return base;
74         }
75         for (LockTarget target : targetLocks) {
76             if (type.getDescriptor().equals(target.getTargetDesc())) {
77                 types.add(target);
78             }
79         }
80 
81         if (types.isEmpty()) {
82             return base;
83         }
84 
85         return new LockTargetState(base.getType(), types);
86     }
87 
88     @Override
merge(BasicValue v1, BasicValue v2)89     public BasicValue merge(BasicValue v1, BasicValue v2) {
90         BasicValue base = super.merge(v1, v2);
91 
92         if (!(v1 instanceof LockTargetState)) {
93             return base;
94         }
95         if (!(v2 instanceof LockTargetState)) {
96             return base;
97         }
98 
99         LockTargetState state1 = (LockTargetState) v1;
100         LockTargetState state2 = (LockTargetState) v2;
101 
102         List<LockTarget> newList = new ArrayList<>(state1.getTargets());
103         for (LockTarget otherTarget : state2.getTargets()) {
104             if (!newList.contains(otherTarget)) {
105                 newList.add(otherTarget);
106             }
107         }
108 
109         return new LockTargetState(base.getType(), newList);
110     }
111 }
112