You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2008/04/15 15:20:54 UTC
svn commit: r648239 [1/4] - in
/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic:
./ analysis/ arithmetic/ functions/ instructions/ trimming/
Author: luc
Date: Tue Apr 15 06:20:36 2008
New Revision: 648239
URL: http://svn.apache.org/viewvc?rev=648239&view=rev
Log:
created bytecode-based automatic differentiation
this implementation uses the ASM bytecode engineering library
it is NOT complete yet!
Added:
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/AutomaticDifferentiator.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ClassDifferentiator.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ErrorReporter.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/InstructionsTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/MethodDifferentiator.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingInterpreter.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingValue.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DAddTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DAddTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DAddTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DDivTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DDivTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DDivTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DMulTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DMulTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DMulTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DNegTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DRemTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DRemTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DRemTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DSubTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DSubTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/arithmetic/DSubTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/AcosTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/AcoshTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/AsinTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/AsinhTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/Atan2Transformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/Atan2Transformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/Atan2Transformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/AtanTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/AtanhTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/CbrtTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/CosTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/CoshTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/ExpTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/Expm1Transformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/HypotTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/HypotTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/HypotTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/Log10Transformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/Log1pTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/LogTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/MathInvocationTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/PowTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/PowTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/PowTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/SinTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/SinhTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/SqrtTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/TanTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/functions/TanhTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/DLoadTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/DReturnTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/DStoreTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/DcmpTransformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/DcmpTransformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/DcmpTransformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/Dup2Transformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/Dup2X1Transformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/Dup2X2Transformer1.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/Dup2X2Transformer12.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/Dup2X2Transformer2.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/NarrowingTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/instructions/WideningTransformer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/trimming/
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/trimming/BytecodeTrimmer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/trimming/DLoadPop2Trimmer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/trimming/SwappedDloadTrimmer.java (with props)
commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/trimming/SwappedDstoreTrimmer.java (with props)
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/AutomaticDifferentiator.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/AutomaticDifferentiator.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/AutomaticDifferentiator.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/AutomaticDifferentiator.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.nabla.core.DifferentialPair;
+import org.apache.commons.nabla.core.DifferentiationException;
+import org.apache.commons.nabla.core.UnivariateDerivative;
+import org.apache.commons.nabla.core.UnivariateDifferentiable;
+import org.apache.commons.nabla.core.UnivariateDifferentiator;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/** Automatic differentiator class based on bytecode analysis.
+ * <p>This class is an implementation of the {@link UnivariateDifferentiator}
+ * interface that computes <em>exact</em> differentials completely automatically
+ * and generate java classes and instances that compute the differential
+ * of the function as if they were hand-coded and compiled.</p>
+ * <p>The derivative bytecode created the first time an instance of a given class
+ * is differentiated is cached and will be reused if other instances of the same class
+ * are to be created later. The cache can also be dumped in a jar file for
+ * use in an application without bringing the full nabla library and its
+ * dependencies.</p>
+ * <p>This differentiator can handle only pure bytecode methods and known methods
+ * from math implementation classes like {@link java.lang.Math Math} or
+ * {@link java.lang.StrictMath StrictMath}. Pure bytecode methods are analyzed
+ * and converted. Methods from math implementation classes are only recognized
+ * by class and name and replaced by predefined derivative code.</p>
+ * @see org.apache.commons.nabla.Fetchdifferentiator
+ */
+public class AutomaticDifferentiator implements UnivariateDifferentiator {
+
+ /** Name for the DifferentialPair class. */
+ public static final String DP_NAME = DifferentialPair.class.getName().replace('.', '/');
+
+ /** Descriptor for the DifferentialPair class. */
+ public static final String DP_DESCRIPTOR = "L" + DP_NAME + ";";
+
+ /** Descriptor for the derivative class f method. */
+ public static final String DP_RETURN_DP_DESCRIPTOR = "(" + DP_DESCRIPTOR + ")" + DP_DESCRIPTOR;
+
+ /** UnivariateDifferentiable/UnivariateDerivative map. */
+ private final HashMap<Class<? extends UnivariateDifferentiable>,
+ Class<? extends UnivariateDerivative>> map;
+
+ /** Math implementation classes. */
+ private final Set<String> mathClasses;
+
+ /** Simple constructor.
+ * <p>Build a AutomaticDifferentiator instance with an empty cache.</p>
+ */
+ public AutomaticDifferentiator() {
+ map = new HashMap<Class<? extends UnivariateDifferentiable>,
+ Class<? extends UnivariateDerivative>>();
+ mathClasses = new HashSet<String>();
+ addMathImplementation(Math.class);
+ addMathImplementation(StrictMath.class);
+ }
+
+ /** Add an implementation class for mathematical functions.
+ * <p>At construction, the differentiator considers only the {@link
+ * java.lang.Math Math} and {@link java.lang.StrictMath StrictMath}
+ * classes are math implementation classes. It may be useful to add
+ * other class for example to add some missing functions like
+ * inverse hyperbolic cosine that are not provided by the standard
+ * java classes as of Java 1.6.</p>
+ * @param mathClass implementation class for mathematical functions
+ */
+ public void addMathImplementation(final Class<?> mathClass) {
+ mathClasses.add(mathClass.getName().replace('.', '/'));
+ }
+
+ /** Dump the cache into a stream.
+ * @param out output stream where to dump the cache
+ */
+ public void dumpCache(final OutputStream out) {
+ // TODO
+ throw new RuntimeException("not implemented yet");
+ }
+
+ /** {@inheritDoc} */
+ public UnivariateDerivative differentiate(final UnivariateDifferentiable d)
+ throws DifferentiationException {
+
+ // get the derivative class
+ final Class<? extends UnivariateDerivative> derivativeClass =
+ getDerivativeClass(d.getClass());
+
+ try {
+
+ // create the instance
+ final Constructor<? extends UnivariateDerivative> constructor =
+ derivativeClass.getConstructor(d.getClass());
+ return constructor.newInstance(d);
+
+ } catch (InstantiationException ie) {
+ throw new DifferentiationException("abstract class {0} cannot be instantiated ({1})",
+ derivativeClass.getName(), ie.getMessage());
+ } catch (IllegalAccessException iae) {
+ throw new DifferentiationException("illegal access to class {0} constructor ({1})",
+ derivativeClass.getName(), iae.getMessage());
+ } catch (NoSuchMethodException nsme) {
+ throw new DifferentiationException("class {0} cannot be built from an instance of class {1} ({2})",
+ derivativeClass.getName(), d.getClass().getName(), nsme.getMessage());
+ } catch (InvocationTargetException ite) {
+ throw new DifferentiationException("class {0} instantiation from an instance of class {1} failed ({2})",
+ derivativeClass.getName(), d.getClass().getName(), ite.getMessage());
+ }
+
+ }
+
+ /** Get the derivative class of a differentiable class.
+ * <p>The derivative class is either built on the fly
+ * or retrieved from the cache if it has been built previously.</p>
+ * @param differentiableClass class to differentiate
+ * @return derivative class
+ * @throws DifferentiationException if the class cannot be differentiated
+ */
+ private Class<? extends UnivariateDerivative>
+ getDerivativeClass(final Class<? extends UnivariateDifferentiable> differentiableClass)
+ throws DifferentiationException {
+
+ // lookup in the map if the class has already been differentiated
+ Class<? extends UnivariateDerivative> derivativeClass =
+ map.get(differentiableClass);
+
+ // build the derivative class if it does not exist yet
+ if (derivativeClass == null) {
+ // perform analytical differentiation
+ derivativeClass = createDerivativeClass(differentiableClass);
+
+ // put the newly created class in the map
+ map.put(differentiableClass, derivativeClass);
+
+ }
+
+ // return the derivative class
+ return derivativeClass;
+
+ }
+
+ /** Build a derivative class of a differentiable class.
+ * @param differentiableClass class to differentiate
+ * @return derivative class
+ * @throws DifferentiationException if the class cannot be differentiated
+ */
+ private Class<? extends UnivariateDerivative>
+ createDerivativeClass(final Class<? extends UnivariateDifferentiable> differentiableClass)
+ throws DifferentiationException {
+ try {
+
+ // set up both ends of the class transform chain
+ final String classResourceName = "/" + differentiableClass.getName().replace('.', '/') + ".class";
+ final InputStream stream = differentiableClass.getResourceAsStream(classResourceName);
+ final ClassReader reader = new ClassReader(stream);
+ final ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
+
+ // differentiate the function embedded in the differentiable class
+ final ClassDifferentiator differentiator = new ClassDifferentiator(mathClasses, writer);
+ reader.accept(differentiator, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ differentiator.reportErrors();
+
+ // create the derivative class
+ return new DerivativeLoader(differentiableClass).defineClass(differentiator, writer);
+
+ } catch (IOException ioe) {
+ throw new DifferentiationException("class {0} cannot be read ({1})",
+ differentiableClass.getName(), ioe.getMessage());
+ }
+ }
+
+ /** Class loader generating derivative classes. */
+ private static class DerivativeLoader extends ClassLoader {
+
+ /** Simple constructor.
+ * @param differentiableClass differentiable class
+ */
+ public DerivativeLoader(final Class<? extends UnivariateDifferentiable> differentiableClass) {
+ super(differentiableClass.getClassLoader());
+ }
+
+ /** Define a derivative class.
+ * @param differentiator class differentiator
+ * @param writer class writer
+ * @return a generated derivative class
+ */
+ @SuppressWarnings("unchecked")
+ public Class<? extends UnivariateDerivative>
+ defineClass(final ClassDifferentiator differentiator, final ClassWriter writer) {
+ final String name = differentiator.getDerivativeClassName().replace('/', '.');
+ final byte[] bytecode = writer.toByteArray();
+ return (Class<? extends UnivariateDerivative>) defineClass(name, bytecode, 0, bytecode.length);
+ }
+ }
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/AutomaticDifferentiator.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ClassDifferentiator.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ClassDifferentiator.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ClassDifferentiator.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ClassDifferentiator.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import java.util.Set;
+
+import org.apache.commons.nabla.core.DifferentiationException;
+import org.apache.commons.nabla.core.UnivariateDerivative;
+import org.apache.commons.nabla.core.UnivariateDifferentiable;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Visitor (in asm sense) for differentiating classes.
+ * <p>
+ * This visitor visits classes implementing the
+ * {@link UnivariateDifferentiable UnivariateDifferentiable} interface and convert
+ * them to classes implementing the {@link UnivariateDerivative
+ * UnivariateDerivative} interface.
+ * </p>
+ * <p>
+ * The visitor creates a new class as an inner class of the visited class.
+ * Instances of the generated class are therefore automatically bound to their
+ * primitive instance which is their directly enclosing instance. As such they
+ * have access to the current value of all fields.
+ * </p>
+ * <p>
+ * The visited class bytecode is not changed at all.
+ * </p>
+ */
+class ClassDifferentiator implements ClassVisitor {
+
+ /** Name for the primitive instance field. */
+ private static final String PRIMITIVE_FIELD = "primitive";
+
+ /** Math implementation classes. */
+ private final Set<String> mathClasses;
+
+ /** Class generating visitor. */
+ private final ClassVisitor generator;
+
+ /** Error reporter. */
+ private final ErrorReporter errorReporter;
+
+ /** Primitive class name. */
+ private String primitiveName;
+
+ /** Descriptor for the primitive class. */
+ private String primitiveDesc;
+
+ /** Derivative class name. */
+ private String derivativeName;
+
+ /** Indicator for specific fields and method addition. */
+ private boolean specificMembersAdded;
+
+ /**
+ * Simple constructor.
+ * @param mathClasses math implementation classes
+ * @param generator visitor to which class generation calls will be delegated
+ */
+ public ClassDifferentiator(final Set<String> mathClasses,
+ final ClassVisitor generator) {
+ this.mathClasses = mathClasses;
+ this.generator = generator;
+ errorReporter = new ErrorReporter();
+ }
+
+ /**
+ * Get the name of the derivative class.
+ * @return name of the (generated) derivative class
+ */
+ public String getDerivativeClassName() {
+ return derivativeName;
+ }
+
+ /** {@inheritDoc} */
+ public void visit(final int version, final int access,
+ final String name, final String signature,
+ final String superName, final String[] interfaces) {
+ // set up the various names
+ primitiveName = name;
+ derivativeName = primitiveName + "$NablaUnivariateDerivative";
+ primitiveDesc = "L" + primitiveName + ";";
+
+ // check the UnivariateDifferentiable interface is implemented
+ final Class<UnivariateDifferentiable> uDerClass = UnivariateDifferentiable.class;
+ boolean isDifferentiable = false;
+ for (String interf : interfaces) {
+ try {
+ isDifferentiable =
+ isDifferentiable || uDerClass.isAssignableFrom(Class.forName(interf.replace('/', '.')));
+ } catch (ClassNotFoundException cnfe) {
+ // simply ignore this inaccessible interface
+ }
+ }
+
+ if (isDifferentiable) {
+ // generate the new class implementing the UnivariateDerivative interface
+ generator.visit(version, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
+ derivativeName, signature, superName,
+ new String[] {
+ UnivariateDerivative.class.getName().replace('.', '/')
+ });
+ } else {
+ errorReporter.register(new DifferentiationException("the {0} class does not implement the {1} interface",
+ name, uDerClass.getName()));
+ }
+
+ specificMembersAdded = false;
+
+ }
+
+ /** {@inheritDoc} */
+ public MethodVisitor visitMethod(final int access, final String name,
+ final String desc, final String signature,
+ final String[] exceptions) {
+
+ // don't do anything if an error has already been encountered
+ if (errorReporter.hasError()) {
+ return null;
+ }
+
+ if (!specificMembersAdded) {
+ // add the specific members we need
+ addPrimitiveField();
+ addConstructor();
+ addGetPrimitive();
+ specificMembersAdded = true;
+ }
+
+ // is it the "public double f(double)" method we want to differentiate ?
+ if (((access & Opcodes.ACC_PUBLIC) == Opcodes.ACC_PUBLIC) &&
+ "f".equals(name) && "(D)D".equals(desc) &&
+ ((exceptions == null) || (exceptions.length == 0))) {
+
+ // get a generator for the method we are going to create
+ final MethodVisitor visitor =
+ generator.visitMethod(access | Opcodes.ACC_SYNTHETIC, name,
+ AutomaticDifferentiator.DP_RETURN_DP_DESCRIPTOR, null, null);
+
+ // make sure our own differentiator will be used to transform the code
+ return new MethodDifferentiator(access, name, desc, signature, exceptions,
+ visitor, primitiveName, mathClasses, errorReporter);
+
+ }
+
+ // we are not interested in this method
+ return null;
+
+ }
+
+ /** {@inheritDoc} */
+ public FieldVisitor visitField(final int access, final String name,
+ final String desc, final String signature,
+ final Object value) {
+ // we are not interested in any fields
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public void visitSource(final String source, final String debug) {
+ }
+
+ /** {@inheritDoc} */
+ public void visitOuterClass(final String owner, final String name,
+ final String desc) {
+ }
+
+ /** {@inheritDoc} */
+ public AnnotationVisitor visitAnnotation(final String desc,
+ final boolean visible) {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public void visitAttribute(final Attribute attr) {
+ }
+
+ /** {@inheritDoc} */
+ public void visitInnerClass(final String name, final String outerName,
+ final String innerName, final int access) {
+ }
+
+ /** {@inheritDoc} */
+ public void visitEnd() {
+
+ // don't do anything if an error has already been encountered
+ if (errorReporter.hasError()) {
+ return;
+ }
+
+ generator.visitEnd();
+
+ }
+
+ /** Add the primitive field.
+ */
+ private void addPrimitiveField() {
+ final FieldVisitor visitor =
+ generator.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
+ PRIMITIVE_FIELD, primitiveDesc, null, null);
+ visitor.visitEnd();
+ }
+
+ /** Add the class constructor.
+ */
+ private void addConstructor() {
+ final String init = "<init>";
+ final MethodVisitor visitor =
+ generator.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, init,
+ "(" + primitiveDesc + ")V", null, null);
+ visitor.visitCode();
+ visitor.visitVarInsn(Opcodes.ALOAD, 0);
+ visitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", init, "()V");
+ visitor.visitVarInsn(Opcodes.ALOAD, 0);
+ visitor.visitVarInsn(Opcodes.ALOAD, 1);
+ visitor.visitFieldInsn(Opcodes.PUTFIELD, derivativeName, PRIMITIVE_FIELD, primitiveDesc);
+ visitor.visitInsn(Opcodes.RETURN);
+ visitor.visitMaxs(0, 0);
+ visitor.visitEnd();
+ }
+
+ /** Add the {@link UnivariateDerivative#getPrimitive() getPrimitive()} method.
+ */
+ private void addGetPrimitive() {
+ final MethodVisitor visitor =
+ generator.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, "getPrimitive",
+ "()" + primitiveDesc, null, null);
+ visitor.visitCode();
+ visitor.visitVarInsn(Opcodes.ALOAD, 0);
+ visitor.visitFieldInsn(Opcodes.GETFIELD, derivativeName, PRIMITIVE_FIELD, primitiveDesc);
+ visitor.visitInsn(Opcodes.ARETURN);
+ visitor.visitMaxs(0, 0);
+ visitor.visitEnd();
+ }
+
+ /** Report the errors that may have occurred during analysis.
+ * @exception DifferentiationException if the derivative class
+ * could not be generated
+ */
+ public void reportErrors() throws DifferentiationException {
+ errorReporter.reportErrors();
+ }
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ClassDifferentiator.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ErrorReporter.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ErrorReporter.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ErrorReporter.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ErrorReporter.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import org.apache.commons.nabla.core.DifferentiationException;
+
+/** Class used for delayed error reporting.
+ */
+public class ErrorReporter {
+
+ /** Error report. */
+ private DifferentiationException reportedError;
+
+ /** Register an exception to be reported later.
+ * @param exception exception to be reported
+ */
+ public void register(final DifferentiationException exception) {
+ reportedError = exception;
+ }
+
+ /** Check if an error has already been registered.
+ * @return true if an error has already been registered
+ */
+ public boolean hasError() {
+ return reportedError != null;
+ }
+
+ /** Report the error if any.
+ * <p>If not error has been reported (i.e. if {@link #hasError()} returns
+ * <code>false</code>), this method does nothing. Otherwise, it rethrows
+ * the original exception.</p>
+ * @exception DifferentiationException if some error occurred
+ * during differentiation
+ */
+ public void reportErrors() throws DifferentiationException {
+ if (reportedError != null) {
+ throw reportedError;
+ }
+ }
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/ErrorReporter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/InstructionsTransformer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/InstructionsTransformer.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/InstructionsTransformer.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/InstructionsTransformer.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import org.apache.commons.nabla.core.DifferentiationException;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnList;
+
+/** Transformer for bytecode instructions.
+ * <p>Transformation is done by replacing a single instruction with
+ * a complete list.</p>
+ */
+public interface InstructionsTransformer {
+
+ /** Get the replacement instructions.
+ * @param original original instruction
+ * @param methodDifferentiator method differentiator driving this transformer
+ * @return replacement instructions
+ * @exception DifferentiationException if the method differentiator cannot provide
+ * a temporary variable
+ */
+ InsnList getReplacement(AbstractInsnNode original,
+ MethodDifferentiator methodDifferentiator)
+ throws DifferentiationException;
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/InstructionsTransformer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/MethodDifferentiator.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/MethodDifferentiator.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/MethodDifferentiator.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/MethodDifferentiator.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,786 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.nabla.automatic.arithmetic.DAddTransformer1;
+import org.apache.commons.nabla.automatic.arithmetic.DAddTransformer12;
+import org.apache.commons.nabla.automatic.arithmetic.DAddTransformer2;
+import org.apache.commons.nabla.automatic.arithmetic.DDivTransformer1;
+import org.apache.commons.nabla.automatic.arithmetic.DDivTransformer12;
+import org.apache.commons.nabla.automatic.arithmetic.DDivTransformer2;
+import org.apache.commons.nabla.automatic.arithmetic.DMulTransformer1;
+import org.apache.commons.nabla.automatic.arithmetic.DMulTransformer12;
+import org.apache.commons.nabla.automatic.arithmetic.DMulTransformer2;
+import org.apache.commons.nabla.automatic.arithmetic.DNegTransformer;
+import org.apache.commons.nabla.automatic.arithmetic.DRemTransformer1;
+import org.apache.commons.nabla.automatic.arithmetic.DRemTransformer12;
+import org.apache.commons.nabla.automatic.arithmetic.DRemTransformer2;
+import org.apache.commons.nabla.automatic.arithmetic.DSubTransformer1;
+import org.apache.commons.nabla.automatic.arithmetic.DSubTransformer12;
+import org.apache.commons.nabla.automatic.arithmetic.DSubTransformer2;
+import org.apache.commons.nabla.automatic.functions.AcosTransformer;
+import org.apache.commons.nabla.automatic.functions.AcoshTransformer;
+import org.apache.commons.nabla.automatic.functions.AsinTransformer;
+import org.apache.commons.nabla.automatic.functions.AsinhTransformer;
+import org.apache.commons.nabla.automatic.functions.Atan2Transformer1;
+import org.apache.commons.nabla.automatic.functions.Atan2Transformer12;
+import org.apache.commons.nabla.automatic.functions.Atan2Transformer2;
+import org.apache.commons.nabla.automatic.functions.AtanTransformer;
+import org.apache.commons.nabla.automatic.functions.AtanhTransformer;
+import org.apache.commons.nabla.automatic.functions.CbrtTransformer;
+import org.apache.commons.nabla.automatic.functions.CosTransformer;
+import org.apache.commons.nabla.automatic.functions.CoshTransformer;
+import org.apache.commons.nabla.automatic.functions.ExpTransformer;
+import org.apache.commons.nabla.automatic.functions.Expm1Transformer;
+import org.apache.commons.nabla.automatic.functions.HypotTransformer1;
+import org.apache.commons.nabla.automatic.functions.HypotTransformer12;
+import org.apache.commons.nabla.automatic.functions.HypotTransformer2;
+import org.apache.commons.nabla.automatic.functions.Log10Transformer;
+import org.apache.commons.nabla.automatic.functions.Log1pTransformer;
+import org.apache.commons.nabla.automatic.functions.LogTransformer;
+import org.apache.commons.nabla.automatic.functions.MathInvocationTransformer;
+import org.apache.commons.nabla.automatic.functions.PowTransformer1;
+import org.apache.commons.nabla.automatic.functions.PowTransformer12;
+import org.apache.commons.nabla.automatic.functions.PowTransformer2;
+import org.apache.commons.nabla.automatic.functions.SinTransformer;
+import org.apache.commons.nabla.automatic.functions.SinhTransformer;
+import org.apache.commons.nabla.automatic.functions.SqrtTransformer;
+import org.apache.commons.nabla.automatic.functions.TanTransformer;
+import org.apache.commons.nabla.automatic.functions.TanhTransformer;
+import org.apache.commons.nabla.automatic.instructions.DLoadTransformer;
+import org.apache.commons.nabla.automatic.instructions.DReturnTransformer;
+import org.apache.commons.nabla.automatic.instructions.DStoreTransformer;
+import org.apache.commons.nabla.automatic.instructions.DcmpTransformer1;
+import org.apache.commons.nabla.automatic.instructions.DcmpTransformer12;
+import org.apache.commons.nabla.automatic.instructions.DcmpTransformer2;
+import org.apache.commons.nabla.automatic.instructions.Dup2Transformer;
+import org.apache.commons.nabla.automatic.instructions.Dup2X1Transformer;
+import org.apache.commons.nabla.automatic.instructions.Dup2X2Transformer1;
+import org.apache.commons.nabla.automatic.instructions.Dup2X2Transformer12;
+import org.apache.commons.nabla.automatic.instructions.Dup2X2Transformer2;
+import org.apache.commons.nabla.automatic.instructions.NarrowingTransformer;
+import org.apache.commons.nabla.automatic.instructions.WideningTransformer;
+import org.apache.commons.nabla.automatic.trimming.DLoadPop2Trimmer;
+import org.apache.commons.nabla.automatic.trimming.SwappedDloadTrimmer;
+import org.apache.commons.nabla.automatic.trimming.SwappedDstoreTrimmer;
+import org.apache.commons.nabla.core.DifferentiationException;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.FieldInsnNode;
+import org.objectweb.asm.tree.IincInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.VarInsnNode;
+import org.objectweb.asm.tree.analysis.Analyzer;
+import org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.objectweb.asm.tree.analysis.BasicValue;
+import org.objectweb.asm.tree.analysis.Frame;
+import org.objectweb.asm.tree.analysis.Interpreter;
+
+/** Class transforming a method computing a value to a method
+ * computing both a value and its differential.
+ */
+public class MethodDifferentiator extends MethodNode {
+
+ /** Descriptor for <code>double f()</code> methods. */
+ private static final String VOID_RETURN_D_DESCRIPTOR = "()D";
+
+ /** Math functions transformer. */
+ private static final Map<String, MathInvocationTransformer> MATH_TRANSFORMERS =
+ new HashMap<String, MathInvocationTransformer>();
+
+ static {
+ MATH_TRANSFORMERS.put("acos", new AcosTransformer());
+ MATH_TRANSFORMERS.put("acosh", new AcoshTransformer());
+ MATH_TRANSFORMERS.put("asin", new AsinTransformer());
+ MATH_TRANSFORMERS.put("asinh", new AsinhTransformer());
+ MATH_TRANSFORMERS.put("atan2_12", new Atan2Transformer12());
+ MATH_TRANSFORMERS.put("atan2_1", new Atan2Transformer1());
+ MATH_TRANSFORMERS.put("atan2_2", new Atan2Transformer2());
+ MATH_TRANSFORMERS.put("atan", new AtanTransformer());
+ MATH_TRANSFORMERS.put("atanh", new AtanhTransformer());
+ MATH_TRANSFORMERS.put("cbrt", new CbrtTransformer());
+ MATH_TRANSFORMERS.put("cos", new CosTransformer());
+ MATH_TRANSFORMERS.put("cosh", new CoshTransformer());
+ MATH_TRANSFORMERS.put("exp", new ExpTransformer());
+ MATH_TRANSFORMERS.put("expm1", new Expm1Transformer());
+ MATH_TRANSFORMERS.put("hypot_12", new HypotTransformer12());
+ MATH_TRANSFORMERS.put("hypot_1", new HypotTransformer1());
+ MATH_TRANSFORMERS.put("hypot_2", new HypotTransformer2());
+ MATH_TRANSFORMERS.put("log10", new Log10Transformer());
+ MATH_TRANSFORMERS.put("log1p", new Log1pTransformer());
+ MATH_TRANSFORMERS.put("log", new LogTransformer());
+ MATH_TRANSFORMERS.put("pow_12", new PowTransformer12());
+ MATH_TRANSFORMERS.put("pow_1", new PowTransformer1());
+ MATH_TRANSFORMERS.put("pow_2", new PowTransformer2());
+ MATH_TRANSFORMERS.put("sin", new SinTransformer());
+ MATH_TRANSFORMERS.put("sinh", new SinhTransformer());
+ MATH_TRANSFORMERS.put("sqrt", new SqrtTransformer());
+ MATH_TRANSFORMERS.put("tan", new TanTransformer());
+ MATH_TRANSFORMERS.put("tanh", new TanhTransformer());
+ }
+
+ /** Message format for unknown method. */
+ private static final String UNKNOWN_METHOD_FMT = "unknown method {0}.{1}";
+
+ /** Maximal number of temporary size 2 variables. */
+ private static final int MAX_TEMP = 5;
+
+ /** Math implementation classes. */
+ private final Set<String> mathClasses;
+
+ /** Generator to use. */
+ private final MethodVisitor generator;
+
+ /** Used locals variables array. */
+ private boolean[] usedLocals;
+
+ /** Primitive class name. */
+ private final String primitiveName;
+
+ /** Error reporter to use. */
+ private final ErrorReporter errorReporter;
+
+ /** Set of converted values. */
+ private final Set<TrackingValue> converted;
+
+ /** Frames for the original method. */
+ private final Map<AbstractInsnNode, Frame> frames;
+
+ /** Instructions successors array. */
+ private final Map<AbstractInsnNode, Set<AbstractInsnNode>> successors;
+
+ /** Cloned labels map. */
+ private final Map<LabelNode, LabelNode> clonedLabels;
+
+ /** Build a differentiator for a method.
+ * @param access access flags of the method
+ * @param name name of the method
+ * @param desc descriptor of the method
+ * @param signature signature of the method
+ * @param exceptions exceptions thrown by the method
+ * @param generator bytecode generator to use for the transformed method
+ * @param primitiveName primitive class name
+ * @param mathClasses math implementation classes
+ * @param errorReporter reporter used for delaying exceptions
+ */
+ public MethodDifferentiator(final int access, final String name, final String desc,
+ final String signature, final String[] exceptions,
+ final MethodVisitor generator,final String primitiveName,
+ final Set<String> mathClasses,
+ final ErrorReporter errorReporter) {
+
+ super(access, name, desc, signature, exceptions);
+ this.generator = generator;
+ this.usedLocals = null;
+ this.primitiveName = primitiveName;
+ this.mathClasses = mathClasses;
+ this.errorReporter = errorReporter;
+ this.converted = new HashSet<TrackingValue>();
+ this.frames = new IdentityHashMap<AbstractInsnNode, Frame>();
+ this.successors = new IdentityHashMap<AbstractInsnNode, Set<AbstractInsnNode>>();
+ this.clonedLabels = new HashMap<LabelNode, LabelNode>();
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void visitEnd() {
+ try {
+
+ // at start, "this" and one differential pair are used
+ maxLocals = 2 * (maxLocals + MAX_TEMP) - 1;
+ usedLocals = new boolean[maxLocals];
+ useLocal(0, 1);
+ useLocal(1, 4);
+
+ // add spare cells to hold new variables if needed
+ addSpareLocalVariables();
+
+ // analyze the original code, tracing values production/consumption
+ final Frame[] array =
+ new FlowAnalyzer(new TrackingInterpreter()).analyze(primitiveName, this);
+
+ // convert the array into a map, since code changes will shift all indices
+ for (int i = 0; i < array.length; ++i) {
+ frames.put(instructions.get(i), array[i]);
+ }
+
+ // identify the needed changes
+ final Set<AbstractInsnNode> changes = identifyChanges();
+
+ if (changes.isEmpty()) {
+
+ // the method does not depend on the parameter at all!
+ // we replace all code by a simple "return DifferentialPair.ZERO;"
+ instructions.clear();
+ instructions.add(new FieldInsnNode(Opcodes.GETSTATIC,
+ AutomaticDifferentiator.DP_NAME,
+ "ZERO",
+ AutomaticDifferentiator.DP_DESCRIPTOR));
+ instructions.add(new InsnNode(Opcodes.ARETURN));
+
+ } else {
+
+ // perform the code changes
+ changeCode(changes);
+
+ // remove the local variables added at the beginning and not used
+ removeUnusedSpareLocalVariables();
+
+ // trim generated instructions list
+ SwappedDloadTrimmer.getInstance().trim(instructions);
+ SwappedDstoreTrimmer.getInstance().trim(instructions);
+ DLoadPop2Trimmer.getInstance().trim(instructions);
+
+ }
+
+ // change the descriptor to its true final value
+ desc = AutomaticDifferentiator.DP_RETURN_DP_DESCRIPTOR;
+
+ // generate the method
+ accept(generator);
+
+ } catch (AnalyzerException ae) {
+ if ((ae.getCause() != null) && ae.getCause() instanceof DifferentiationException) {
+ errorReporter.register((DifferentiationException) ae.getCause());
+ } else {
+ final DifferentiationException de =
+ new DifferentiationException("unable to analyze the {0}.{1} method ({2})",
+ new Object[] {
+ primitiveName, name, ae.getMessage()
+ });
+ errorReporter.register(de);
+ }
+ } catch (DifferentiationException de) {
+ errorReporter.register(de);
+ }
+ }
+
+ /** Add spare cells for new local variables.
+ * <p>In order to ease conversion from double values to differential pairs,
+ * we start by reserving one spare cell between each original local variables.
+ * So we have to modify the indices in all instructions referencing local
+ * variables in the original code, to take into account the renumbering
+ * introduced by these spare cells. The spare cells by themselves will
+ * be referenced by the converted instructions in the following passes.</p>
+ * <p>The spare cells that will not be used will be reclaimed after
+ * conversion, to avoid wasting memory.</p>
+ * @exception DifferentiationException if local variables array has not been
+ * expanded appropriately beforehand
+ * @see #removeUnusedSpareLocalVariables()
+ */
+ private void addSpareLocalVariables() throws DifferentiationException {
+ for (final Iterator<?> i = instructions.iterator(); i.hasNext();) {
+ final AbstractInsnNode insn = (AbstractInsnNode) i.next();
+ if (insn.getType() == AbstractInsnNode.VAR_INSN) {
+ final VarInsnNode varInsn = (VarInsnNode) insn;
+ if (varInsn.var > 2) {
+ varInsn.var = 2 * varInsn.var - 1;
+ final int opcode = varInsn.getOpcode();
+ if ((opcode == Opcodes.ILOAD) || (opcode == Opcodes.FLOAD) ||
+ (opcode == Opcodes.ALOAD) || (opcode == Opcodes.ISTORE) ||
+ (opcode == Opcodes.FSTORE) || (opcode == Opcodes.ASTORE)) {
+ useLocal(varInsn.var, 1);
+ } else {
+ useLocal(varInsn.var, 2);
+ }
+ }
+ } else if (insn.getOpcode() == Opcodes.IINC) {
+ final IincInsnNode iincInsn = (IincInsnNode) insn;
+ if (iincInsn.var > 2) {
+ iincInsn.var = 2 * iincInsn.var - 1;
+ useLocal(iincInsn.var, 1);
+ }
+ }
+ }
+ }
+
+ /** Remove the unused spare cells introduced at conversion start.
+ * @see #addSpareLocalVariables()
+ */
+ private void removeUnusedSpareLocalVariables() {
+ for (final Iterator<?> i = instructions.iterator(); i.hasNext();) {
+ final AbstractInsnNode insn = (AbstractInsnNode) i.next();
+ if (insn.getType() == AbstractInsnNode.VAR_INSN) {
+ shiftVariable((VarInsnNode) insn);
+ }
+ }
+ }
+
+ /** Identify the instructions that must be changed.
+ * <p>Identification is based on data flow analysis. We start by changing
+ * the local variables in the initial frame to match the parameters of
+ * the derivative method, and propagate these variables following the
+ * instructions path, updating stack cells and local variables as needed.
+ * Instructions that must be changed are the ones that consume changed
+ * variables or stack cells.</p>
+ * @return set containing all the instructions that must be changed
+ */
+ private Set<AbstractInsnNode> identifyChanges() {
+
+ // the pending set contains the values (local variables or stack cells)
+ // that have been changed, they will trigger changes on the instructions
+ // that consume them
+ final Set<TrackingValue> pending = new HashSet<TrackingValue>();
+
+ // the changes set contains the instructions that must be changed
+ final Set<AbstractInsnNode> changes = new HashSet<AbstractInsnNode>();
+
+ // start by converting the parameter of the method,
+ // which is kept in local variable 1 of the initial frame
+ final TrackingValue dpParameter = (TrackingValue) frames.get(instructions.get(0)).getLocal(1);
+ pending.add(dpParameter);
+
+ // propagate the values conversions throughout the method
+ while (!pending.isEmpty()) {
+
+ // pop one element from the set of changed values
+ final Iterator<TrackingValue> iterator = pending.iterator();
+ final TrackingValue value = iterator.next();
+ iterator.remove();
+
+ // this value is converted
+ converted.add(value);
+
+ // check the consumers instructions for this value
+ for (final AbstractInsnNode consumer : value.getConsumers()) {
+
+ // an instruction consuming a converted value and producing
+ // a double must be changed to produce a differential pair,
+ // get the double values produced and add them to the changed set
+ for (TrackingValue produced : getProducedDoubleValues(consumer)) {
+
+ // add it to the pending set if it has not already been processed
+ if (!converted.contains(produced)) {
+ pending.add(produced);
+ }
+
+ }
+
+ // as a consumer of a converted value, the instruction must be changed
+ changes.add(consumer);
+
+ }
+
+ // check the producers instructions for this value
+ for (final AbstractInsnNode producer : value.getProducers()) {
+
+ // an instruction producing a converted value must be changed
+ changes.add(producer);
+
+ }
+ }
+
+ return changes;
+
+ }
+
+ /** Get the list of double values produced by an instruction.
+ * @param instruction instruction producing the values
+ * @return list of double values produced
+ */
+ private List<TrackingValue> getProducedDoubleValues(final AbstractInsnNode instruction) {
+
+ final List<TrackingValue> values = new ArrayList<TrackingValue>();
+
+ // get the frame before instruction execution
+ final Frame before = frames.get(instruction);
+ final int beforeStackSize = before.getStackSize();
+ final int locals = before.getLocals();
+
+ // check the frames produced by this instruction
+ // (they correspond to the input frames of its successors)
+ final Set<AbstractInsnNode> set = successors.get(instruction);
+ if (set != null) {
+
+ // loop over the successors of this instruction
+ for (final AbstractInsnNode successor : set) {
+ final Frame produced = frames.get(successor);
+
+ // check the stack cells
+ for (int i = 0; i < produced.getStackSize(); ++i) {
+ final TrackingValue value = (TrackingValue) produced.getStack(i);
+ if (((i >= beforeStackSize) || (value != before.getStack(i))) &&
+ value.getValue().equals(BasicValue.DOUBLE_VALUE)) {
+ values.add(value);
+ }
+ }
+
+ // check the local variables
+ for (int i = 0; i < locals; ++i) {
+ final TrackingValue value = (TrackingValue) produced.getLocal(i);
+ if ((value != before.getLocal(i)) &&
+ value.getValue().equals(BasicValue.DOUBLE_VALUE)) {
+ values.add(value);
+ }
+ }
+ }
+ }
+
+ return values;
+
+ }
+
+ /** Perform the code changes.
+ * @param changes instructions that must be changed
+ * @exception DifferentiationException if some instruction cannot be handled
+ */
+ private void changeCode(final Set<AbstractInsnNode> changes)
+ throws DifferentiationException {
+
+ // insert the parameter conversion code at method start
+ final InsnList list = new InsnList();
+ list.add(new VarInsnNode(Opcodes.ALOAD, 1));
+ list.add(new InsnNode(Opcodes.DUP));
+ list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, AutomaticDifferentiator.DP_NAME, "getU0",
+ VOID_RETURN_D_DESCRIPTOR));
+ list.add(new VarInsnNode(Opcodes.DSTORE, 1));
+ list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, AutomaticDifferentiator.DP_NAME, "getU1",
+ VOID_RETURN_D_DESCRIPTOR));
+ list.add(new VarInsnNode(Opcodes.DSTORE, 3));
+
+ instructions.insertBefore(instructions.get(0), list);
+
+ // transform the existing instructions
+ for (final AbstractInsnNode insn : changes) {
+ instructions.insert(insn, getReplacement(insn));
+ instructions.remove(insn);
+ }
+
+ }
+
+ /** Get the replacement list for an instruction.
+ * @param insn instruction to replace
+ * @return replacement instructions list
+ * @exception DifferentiationException if some instruction cannot be handled
+ * or if no temporary variable can be reserved
+ */
+ private InsnList getReplacement(final AbstractInsnNode insn)
+ throws DifferentiationException {
+
+ // get the frame at the start of the instruction
+ final Frame frame = frames.get(insn);
+ final int size = frame.getStackSize();
+ final boolean stack1Converted = (size > 0) && converted.contains(frame.getStack(size - 2));
+ final boolean stack0Converted = (size > 1) && converted.contains(frame.getStack(size - 1));
+
+ switch(insn.getOpcode()) {
+ case Opcodes.DLOAD :
+ useLocal(((VarInsnNode) insn).var, 4);
+ return DLoadTransformer.getInstance().getReplacement(insn, this);
+ case Opcodes.DALOAD :
+ // TODO DALOAD
+ throw new RuntimeException("DALOAD not handled yet");
+ case Opcodes.DSTORE :
+ useLocal(((VarInsnNode) insn).var, 4);
+ return DStoreTransformer.getInstance().getReplacement(insn, this);
+ case Opcodes.DASTORE :
+ // TODO DASTORE
+ throw new RuntimeException("DASTORE not handled yet");
+ case Opcodes.DUP2 :
+ return Dup2Transformer.getInstance().getReplacement(insn, this);
+ case Opcodes.DUP2_X1 :
+ return Dup2X1Transformer.getInstance().getReplacement(insn, this);
+ case Opcodes.DUP2_X2 :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return Dup2X2Transformer12.getInstance().getReplacement(insn, this);
+ }
+ return Dup2X2Transformer1.getInstance().getReplacement(insn, this);
+ }
+ return Dup2X2Transformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DADD :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return DAddTransformer12.getInstance().getReplacement(insn, this);
+ }
+ return DAddTransformer1.getInstance().getReplacement(insn, this);
+ }
+ return DAddTransformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DSUB :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return DSubTransformer12.getInstance().getReplacement(insn, this);
+ }
+ return DSubTransformer1.getInstance().getReplacement(insn, this);
+ }
+ return DSubTransformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DMUL :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return DMulTransformer12.getInstance().getReplacement(insn, this);
+ }
+ return DMulTransformer1.getInstance().getReplacement(insn, this);
+ }
+ return DMulTransformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DDIV :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return DDivTransformer12.getInstance().getReplacement(insn, this);
+ }
+ return DDivTransformer1.getInstance().getReplacement(insn, this);
+ }
+ return DDivTransformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DREM :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return DRemTransformer12.getInstance().getReplacement(insn, this);
+ }
+ return DRemTransformer1.getInstance().getReplacement(insn, this);
+ }
+ return DRemTransformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DNEG :
+ return DNegTransformer.getInstance().getReplacement(insn, this);
+ case Opcodes.DCONST_0 :
+ case Opcodes.DCONST_1 :
+ case Opcodes.LDC :
+ case Opcodes.I2D :
+ case Opcodes.L2D :
+ case Opcodes.F2D :
+ return WideningTransformer.getInstance().getReplacement(insn, this);
+ case Opcodes.POP2 :
+ case Opcodes.D2I :
+ case Opcodes.D2L :
+ case Opcodes.D2F :
+ return NarrowingTransformer.getInstance().getReplacement(insn, this);
+ case Opcodes.DCMPL :
+ case Opcodes.DCMPG :
+ if (stack1Converted) {
+ if (stack0Converted) {
+ return DcmpTransformer12.getInstance().getReplacement(insn, this);
+ }
+ return DcmpTransformer1.getInstance().getReplacement(insn, this);
+ }
+ return DcmpTransformer2.getInstance().getReplacement(insn, this);
+ case Opcodes.DRETURN :
+ return DReturnTransformer.getInstance().getReplacement(insn, this);
+ case Opcodes.GETSTATIC :
+ // TODO GETSTATIC
+ throw new RuntimeException("GETSTATIC not handled yet");
+ case Opcodes.PUTSTATIC :
+ // TODO PUTSTATIC
+ throw new RuntimeException("PUTSTATIC not handled yet");
+ case Opcodes.GETFIELD :
+ // TODO GETFIELD
+ throw new RuntimeException("GETFIELD not handled yet");
+ case Opcodes.PUTFIELD :
+ // TODO PUTFIELD
+ throw new RuntimeException("PUTFIELD not handled yet");
+ case Opcodes.INVOKEVIRTUAL :
+ // TODO INVOKEVIRTUAL
+ throw new RuntimeException("INVOKEVIRTUAL not handled yet");
+ case Opcodes.INVOKESPECIAL :
+ // TODO INVOKESPECIAL
+ throw new RuntimeException("INVOKESPECIAL not handled yet");
+ case Opcodes.INVOKESTATIC :
+ return replaceInvocation((MethodInsnNode) insn,
+ stack1Converted, stack0Converted);
+ case Opcodes.INVOKEINTERFACE :
+ // TODO INVOKEINTERFACE
+ throw new RuntimeException("INVOKEINTERFACE not handled yet");
+ case Opcodes.NEWARRAY :
+ // TODO NEWARRAY
+ throw new RuntimeException("NEWARRAY not handled yet");
+ case Opcodes.ANEWARRAY :
+ // TODO ANEWARRAY
+ throw new RuntimeException("ANEWARRAY not handled yet");
+ case Opcodes.MULTIANEWARRAY :
+ // TODO MULTIANEWARRAY
+ throw new RuntimeException("MULTIANEWARRAY not handled yet");
+ default:
+ throw new DifferentiationException("unable to handle instruction with opcode {0}",
+ new Object[] {
+ Integer.valueOf(insn.getOpcode())
+ });
+ }
+
+ }
+
+ /** Replace an INVOKESTATIC instruction.
+ * @param methodInsn invocation instruction
+ * @param stack1Converted if true, the stack sub-head has been
+ * converted to differential pair
+ * @param stack0Converted if true, the stack head has been
+ * converted to differential pair
+ * @return replacement instructions list
+ * @exception DifferentiationException if the instruction cannot be replaced
+ */
+ private InsnList replaceInvocation(final MethodInsnNode methodInsn,
+ final boolean stack1Converted,
+ final boolean stack0Converted)
+ throws DifferentiationException {
+ if (isMathImplementationClass(methodInsn.owner)) {
+ if ("(D)D".equals(methodInsn.desc)) {
+ // this is a univariate method like sin, cos, exp ...
+ final MathInvocationTransformer transformer = MATH_TRANSFORMERS.get(methodInsn.name);
+ if (transformer == null) {
+ throw new DifferentiationException(UNKNOWN_METHOD_FMT,
+ methodInsn.owner, methodInsn.name);
+ }
+ return transformer.getReplacementList(methodInsn.owner, this);
+ } else if ("(DD)D".equals(methodInsn.desc)) {
+ // this is a bivariate method like atan2, pow ...
+
+ // we may want to differentiate against first, second or both parameters
+ String name = null;
+ if (stack1Converted) {
+ if (stack0Converted) {
+ name = methodInsn.name + "_12";
+ } else {
+ name = methodInsn.name + "_1";
+ }
+ } else if (stack0Converted) {
+ name = methodInsn.name + "_2";
+ }
+
+ if (name != null) {
+ final MathInvocationTransformer transformer = MATH_TRANSFORMERS.get(name);
+ if (transformer == null) {
+ throw new DifferentiationException(UNKNOWN_METHOD_FMT,
+ methodInsn.owner, methodInsn.name);
+ }
+ return transformer.getReplacementList(methodInsn.owner, this);
+ }
+ }
+ }
+ throw new DifferentiationException("unexpected instruction {0}",
+ Integer.valueOf(methodInsn.getOpcode()));
+ }
+
+ /** Test if a class is a math implementation class.
+ * @param name name of the class to test
+ * @return true if the named class is a math implementation class
+ */
+ public boolean isMathImplementationClass(final String name) {
+ return mathClasses.contains(name);
+ }
+
+ /** Set a local variable as used by the modified code.
+ * @param index index of the variable
+ * @param size size of the variable (1 or 2 for standard variables,
+ * 4 for special expanded differential pairs)
+ * @exception DifferentiationException if the number of the
+ * temporary variable lies outside of the allowed range
+ */
+ public void useLocal(final int index, final int size)
+ throws DifferentiationException {
+ if ((index < 0) || ((index + size - 1) >= usedLocals.length)) {
+ throw new DifferentiationException("index of size {0} local variable ({1}) " +
+ "outside of [{2}, {3}] range",
+ Integer.valueOf(size), Integer.valueOf(index),
+ Integer.valueOf(1), Integer.valueOf(MAX_TEMP));
+ }
+ for (int i = index; i < index + size; ++i) {
+ usedLocals[i] = true;
+ }
+ }
+
+ /** Get index of a size 2 temporary variable.
+ * <p>Temporary variables can be used for very short duration
+ * storage of size 2 values (i.e one double, or one long or two
+ * integers). These variables are reused in many replacement
+ * instructions sequences, so their content may be overridden
+ * at any time: they should be considered to have a scope
+ * limited to one replacement sequence only. This means that
+ * one should <em>not</em> store a value in a variable in one
+ * replacement sequence and retrieve it later in another
+ * replacement sequence as it may have been overridden in
+ * between.</p>
+ * <p>At most 5 temporary variables may be used.</p>
+ * @param number number of the temporary variable (must be
+ * between 1 and the maximal number of available temporary
+ * variables)
+ * @return index of the variable within the local variables
+ * array
+ * @exception DifferentiationException if the number of the
+ * temporary variable lies outside of the allowed range
+ */
+ public int getTmp(final int number) throws DifferentiationException {
+ if ((number < 0) || (number > MAX_TEMP)) {
+ throw new DifferentiationException("number of temporary variable ({0}) outside of [{1}, {2}] range",
+ Integer.valueOf(number),
+ Integer.valueOf(1),
+ Integer.valueOf(MAX_TEMP));
+ }
+ final int index = usedLocals.length - 2 * number;
+ useLocal(index, 2);
+ return index;
+ }
+
+ /** Shifted the index of a variable instruction.
+ * @param insn variable instruction
+ */
+ public void shiftVariable(final VarInsnNode insn) {
+ int shifted = 0;
+ for (int i = 0; i < insn.var; ++i) {
+ if (usedLocals[i]) {
+ ++shifted;
+ }
+ }
+ insn.var = shifted;
+ }
+
+ /** Clone an instruction.
+ * @param insn instruction to clone
+ * @return cloned instruction
+ */
+ public AbstractInsnNode clone(final AbstractInsnNode insn) {
+ return insn.clone(clonedLabels);
+ }
+
+ /** Analyzer preserving instructions successors information. */
+ private class FlowAnalyzer extends Analyzer {
+
+ /** Simple constructor.
+ * @param interpreter associated interpreter
+ */
+ public FlowAnalyzer(final Interpreter interpreter) {
+ super(interpreter);
+ }
+
+ /** Store a new edge.
+ * @param insn current instruction
+ * @param successor successor instruction
+ */
+ protected void newControlFlowEdge(final int insn, final int successor) {
+ // store the successor information
+ final AbstractInsnNode node = instructions.get(insn);
+ Set<AbstractInsnNode> set = successors.get(node);
+ if (set == null) {
+ set = new HashSet<AbstractInsnNode>();
+ successors.put(node, set);
+ }
+ set.add(instructions.get(successor));
+ }
+
+ }
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/MethodDifferentiator.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingInterpreter.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingInterpreter.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingInterpreter.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingInterpreter.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.objectweb.asm.tree.analysis.BasicInterpreter;
+import org.objectweb.asm.tree.analysis.BasicValue;
+import org.objectweb.asm.tree.analysis.Value;
+
+/** An interpreter tracking which instructions use which values.
+ * <p>This interpreter wraps {@link org.objectweb.asm.tree.analysis.BasicValue
+ * BasicValue} instances into {@link TrackingValue TrackingValue} instances.</p>
+ */
+public class TrackingInterpreter extends BasicInterpreter {
+
+ /** Build an interpreter.
+ */
+ public TrackingInterpreter() {
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value newValue(final Type type) {
+ return (type == null) ? TrackingValue.UNINITIALIZED_VALUE : wrap(super.newValue(type), null);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value newOperation(final AbstractInsnNode insn) {
+ return wrap(super.newOperation(insn), insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value unaryOperation(final AbstractInsnNode insn,
+ final Value value)
+ throws AnalyzerException {
+ ((TrackingValue) value).addConsumer(insn);
+ return wrap(super.unaryOperation(insn, value), insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value binaryOperation(final AbstractInsnNode insn,
+ final Value value1, final Value value2)
+ throws AnalyzerException {
+ ((TrackingValue) value1).addConsumer(insn);
+ ((TrackingValue) value2).addConsumer(insn);
+ return wrap(super.binaryOperation(insn, value1, value2), insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value ternaryOperation(final AbstractInsnNode insn,
+ final Value value1, final Value value2,
+ final Value value3)
+ throws AnalyzerException {
+ ((TrackingValue) value1).addConsumer(insn);
+ ((TrackingValue) value2).addConsumer(insn);
+ ((TrackingValue) value3).addConsumer(insn);
+ return wrap(super.ternaryOperation(insn, value1, value2, value3), insn);
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Value naryOperation(final AbstractInsnNode insn,
+ final List values)
+ throws AnalyzerException {
+ for (final Iterator<?> iterator = values.iterator(); iterator.hasNext();) {
+ ((TrackingValue) iterator.next()).addConsumer(insn);
+ }
+ return wrap(super.naryOperation(insn, values), insn);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value copyOperation(final AbstractInsnNode insn,
+ final Value value)
+ throws AnalyzerException {
+ // we reuse the same instance instead of wrapping it again
+ // thus simplifying transitive dependencies propagation
+ final TrackingValue tv = (TrackingValue) value;
+ tv.addConsumer(insn);
+ tv.addProducer(insn);
+ return value;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Value merge(final Value v, final Value w) {
+
+ final TrackingValue tv = (TrackingValue) v;
+ final TrackingValue tw = (TrackingValue) w;
+ TrackingValue.merge(tv, tw);
+
+ final BasicValue superMerged = (BasicValue) super.merge(tv.getValue(), tw.getValue());
+ return (superMerged == tv.getValue()) ? tv : new TrackingValue(superMerged);
+
+ }
+
+ /** Wrap a value returned by the superclass.
+ * @param value underlying value (may be null)
+ * @param producer instruction producing the value (may be null)
+ * @return the wrapped value
+ */
+ private TrackingValue wrap(final Value value,
+ final AbstractInsnNode producer) {
+
+ if (value == null) {
+ return null;
+ }
+
+ // values produced by the superclass are either BasicValue instances
+ // (like BasicValue.DOUBLE_VALUE) or already TrackingValue if the
+ // superclass called our local implementation of newValue or newOperation
+ final TrackingValue tv = (value instanceof TrackingValue) ?
+ (TrackingValue) value :
+ new TrackingValue((BasicValue) value);
+
+ if (producer != null) {
+ tv.addProducer(producer);
+ }
+
+ return tv;
+
+ }
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingInterpreter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingValue.java
URL: http://svn.apache.org/viewvc/commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingValue.java?rev=648239&view=auto
==============================================================================
--- commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingValue.java (added)
+++ commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingValue.java Tue Apr 15 06:20:36 2008
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.nabla.automatic.analysis;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.analysis.BasicValue;
+import org.objectweb.asm.tree.analysis.Value;
+
+/** A value that keep track of both instructions producing and consuming it.
+ */
+public class TrackingValue implements Value {
+
+ /** Special value for uninitialized values. */
+ public static final TrackingValue UNINITIALIZED_VALUE =
+ new TrackingValue((BasicValue) BasicValue.UNINITIALIZED_VALUE);
+
+ /** Underlying value. */
+ private final BasicValue value;
+
+ /** Instructions that consume this value. */
+ private Set<AbstractInsnNode> consumers;
+
+ /** Instructions that produce this value. */
+ private Set<AbstractInsnNode> producers;
+
+ /** Values that are merged with this value. */
+ private Set<TrackingValue> merged;
+
+ /** Build a new value without any link to instructions.
+ * @param value wrapped {@link BasicValue} value
+ */
+ public TrackingValue(final BasicValue value) {
+ this.value = value;
+ consumers = new HashSet<AbstractInsnNode>();
+ producers = new HashSet<AbstractInsnNode>();
+ merged = new HashSet<TrackingValue>();
+ }
+
+ /** Get the wrapped {@link BasicValue}.
+ * @return wrapped {@link BasicValue}
+ */
+ public BasicValue getValue() {
+ return value;
+ }
+
+ /** {@inheritDoc} */
+ public int getSize() {
+ return value.getSize();
+ }
+
+ /** Add a consumer for this value.
+ * @param consumer consumer for this value
+ */
+ public void addConsumer(final AbstractInsnNode consumer) {
+ consumers.add(consumer);
+ }
+
+ /** Get the consumers for this value and all values it is merged with.
+ * @return the instructions consuming either this value or the values
+ * it has been merged with
+ */
+ public Set<AbstractInsnNode> getConsumers() {
+ return consumers;
+ }
+
+ /** Add a producer for this value.
+ * @param producer producer for this value
+ */
+ public void addProducer(final AbstractInsnNode producer) {
+ producers.add(producer);
+ }
+
+ /** Get the producers for this value and all values it is merged with.
+ * @return the instructions producing either this value or the values
+ * it has been merged with
+ */
+ public Set<AbstractInsnNode> getProducers() {
+ return producers;
+ }
+
+ /** Merge two instances.
+ * <p>Once merged, values share the same producers and consumers sets.</p>
+ * @param value1 first value to merge
+ * @param value2 second value to merge
+ */
+ public static void merge(final TrackingValue value1,
+ final TrackingValue value2) {
+
+ // merge the sets
+ value1.consumers.addAll(value2.consumers);
+ value1.producers.addAll(value2.producers);
+ value1.merged.addAll(value2.merged);
+
+ // share the merged sets
+ for (TrackingValue value : value2.merged) {
+ value.consumers = value1.consumers;
+ value.producers = value1.producers;
+ value.merged = value1.merged;
+ }
+ value2.consumers = value1.consumers;
+ value2.producers = value1.producers;
+ value2.merged = value1.merged;
+
+ }
+
+}
Propchange: commons/sandbox/nabla/trunk/src/main/java/org/apache/commons/nabla/automatic/analysis/TrackingValue.java
------------------------------------------------------------------------------
svn:eol-style = native