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