Home | History | Annotate | Download | only in lockedregioncodeinjection
      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