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 java.util.ArrayList; 17 import java.util.List; 18 import org.objectweb.asm.Type; 19 import org.objectweb.asm.tree.AbstractInsnNode; 20 import org.objectweb.asm.tree.MethodInsnNode; 21 import org.objectweb.asm.tree.analysis.AnalyzerException; 22 import org.objectweb.asm.tree.analysis.BasicInterpreter; 23 import org.objectweb.asm.tree.analysis.BasicValue; 24 25 /** 26 * A simple dataflow analysis to determine if the operands on the stack must be one of target lock 27 * class type. 28 */ 29 public class LockTargetStateAnalysis extends BasicInterpreter { 30 31 private final List<LockTarget> targetLocks; 32 33 public LockTargetStateAnalysis(List<LockTarget> targetLocks) { 34 this.targetLocks = targetLocks; 35 } 36 37 @Override 38 public BasicValue naryOperation(AbstractInsnNode inst, @SuppressWarnings("rawtypes") List args) 39 throws AnalyzerException { 40 // We target the return type of any invocation. 41 42 @SuppressWarnings("unchecked") 43 BasicValue base = super.naryOperation(inst, args); 44 if (!(inst instanceof MethodInsnNode)) { 45 return base; 46 } 47 48 MethodInsnNode invoke = (MethodInsnNode) inst; 49 Type returnType = Type.getReturnType(invoke.desc); 50 if (returnType.equals(Type.VOID_TYPE)) { 51 return base; 52 } 53 54 List<LockTarget> types = new ArrayList<>(); 55 56 for (LockTarget target : targetLocks) { 57 if (returnType.getDescriptor().equals(target.getTargetDesc())) { 58 types.add(target); 59 } 60 } 61 62 return new LockTargetState(base.getType(), types); 63 } 64 65 @Override 66 public BasicValue newValue(Type type) { 67 BasicValue base = super.newValue(type); 68 List<LockTarget> types = new ArrayList<>(); 69 70 if (type == null) { 71 return base; 72 } 73 for (LockTarget target : targetLocks) { 74 if (type.getDescriptor().equals(target.getTargetDesc())) { 75 types.add(target); 76 } 77 } 78 79 if (types.isEmpty()) { 80 return base; 81 } 82 83 return new LockTargetState(base.getType(), types); 84 } 85 86 @Override 87 public BasicValue merge(BasicValue v1, BasicValue v2) { 88 BasicValue base = super.merge(v1, v2); 89 90 if (!(v1 instanceof LockTargetState)) { 91 return base; 92 } 93 if (!(v2 instanceof LockTargetState)) { 94 return base; 95 } 96 97 LockTargetState state1 = (LockTargetState) v1; 98 LockTargetState state2 = (LockTargetState) v2; 99 100 List<LockTarget> newList = new ArrayList<>(state1.getTargets()); 101 for (LockTarget otherTarget : state2.getTargets()) { 102 if (!newList.contains(otherTarget)) { 103 newList.add(otherTarget); 104 } 105 } 106 107 return new LockTargetState(base.getType(), newList); 108 } 109 } 110