001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.nabla.algorithmic.forward.analysis; 018 019 import java.util.Iterator; 020 import java.util.List; 021 022 import org.objectweb.asm.Type; 023 import org.objectweb.asm.tree.AbstractInsnNode; 024 import org.objectweb.asm.tree.analysis.AnalyzerException; 025 import org.objectweb.asm.tree.analysis.BasicInterpreter; 026 import org.objectweb.asm.tree.analysis.BasicValue; 027 import org.objectweb.asm.tree.analysis.Value; 028 029 /** An interpreter tracking which instructions use which values. 030 * <p>This interpreter wraps {@link org.objectweb.asm.tree.analysis.BasicValue 031 * BasicValue} instances into {@link TrackingValue TrackingValue} instances.</p> 032 */ 033 public class TrackingInterpreter extends BasicInterpreter { 034 035 /** Build an interpreter. 036 */ 037 public TrackingInterpreter() { 038 } 039 040 /** {@inheritDoc} */ 041 @Override 042 public Value newValue(final Type type) { 043 return (type == null) ? TrackingValue.UNINITIALIZED_VALUE : wrap(super.newValue(type), null); 044 } 045 046 /** {@inheritDoc} */ 047 @Override 048 public Value newOperation(final AbstractInsnNode insn) throws AnalyzerException { 049 return wrap(super.newOperation(insn), insn); 050 } 051 052 /** {@inheritDoc} */ 053 @Override 054 public Value unaryOperation(final AbstractInsnNode insn, 055 final Value value) 056 throws AnalyzerException { 057 ((TrackingValue) value).addConsumer(insn); 058 return wrap(super.unaryOperation(insn, value), insn); 059 } 060 061 /** {@inheritDoc} */ 062 @Override 063 public Value binaryOperation(final AbstractInsnNode insn, 064 final Value value1, final Value value2) 065 throws AnalyzerException { 066 ((TrackingValue) value1).addConsumer(insn); 067 ((TrackingValue) value2).addConsumer(insn); 068 return wrap(super.binaryOperation(insn, value1, value2), insn); 069 } 070 071 /** {@inheritDoc} */ 072 @Override 073 public Value ternaryOperation(final AbstractInsnNode insn, 074 final Value value1, final Value value2, 075 final Value value3) 076 throws AnalyzerException { 077 ((TrackingValue) value1).addConsumer(insn); 078 ((TrackingValue) value2).addConsumer(insn); 079 ((TrackingValue) value3).addConsumer(insn); 080 return wrap(super.ternaryOperation(insn, value1, value2, value3), insn); 081 } 082 083 /** {@inheritDoc} */ 084 @SuppressWarnings("unchecked") 085 @Override 086 public Value naryOperation(final AbstractInsnNode insn, 087 final List values) 088 throws AnalyzerException { 089 for (final Iterator<?> iterator = values.iterator(); iterator.hasNext();) { 090 ((TrackingValue) iterator.next()).addConsumer(insn); 091 } 092 return wrap(super.naryOperation(insn, values), insn); 093 } 094 095 /** {@inheritDoc} */ 096 @Override 097 public Value copyOperation(final AbstractInsnNode insn, 098 final Value value) 099 throws AnalyzerException { 100 // we reuse the same instance instead of wrapping it again 101 // thus simplifying transitive dependencies propagation 102 final TrackingValue tv = (TrackingValue) value; 103 tv.addConsumer(insn); 104 tv.addProducer(insn); 105 return value; 106 } 107 108 /** {@inheritDoc} */ 109 @Override 110 public Value merge(final Value v, final Value w) { 111 112 final TrackingValue tv = (TrackingValue) v; 113 final TrackingValue tw = (TrackingValue) w; 114 TrackingValue.merge(tv, tw); 115 116 final BasicValue superMerged = (BasicValue) super.merge(tv.getValue(), tw.getValue()); 117 return (superMerged == tv.getValue()) ? tv : new TrackingValue(superMerged); 118 119 } 120 121 /** Wrap a value returned by the superclass. 122 * @param value underlying value (may be null) 123 * @param producer instruction producing the value (may be null) 124 * @return the wrapped value 125 */ 126 private TrackingValue wrap(final Value value, 127 final AbstractInsnNode producer) { 128 129 if (value == null) { 130 return null; 131 } 132 133 // values produced by the superclass are either BasicValue instances 134 // (like BasicValue.DOUBLE_VALUE) or already TrackingValue if the 135 // superclass called our local implementation of newValue or newOperation 136 final TrackingValue tv = (value instanceof TrackingValue) ? 137 (TrackingValue) value : 138 new TrackingValue((BasicValue) value); 139 140 if (producer != null) { 141 tv.addProducer(producer); 142 } 143 144 return tv; 145 146 } 147 148 }