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.instructions; 018 019 import org.apache.commons.nabla.algorithmic.forward.analysis.InstructionsTransformer; 020 import org.apache.commons.nabla.algorithmic.forward.analysis.MethodDifferentiator; 021 import org.apache.commons.nabla.core.DifferentiationException; 022 import org.objectweb.asm.Opcodes; 023 import org.objectweb.asm.tree.AbstractInsnNode; 024 import org.objectweb.asm.tree.InsnList; 025 import org.objectweb.asm.tree.InsnNode; 026 import org.objectweb.asm.tree.MethodInsnNode; 027 import org.objectweb.asm.tree.TypeInsnNode; 028 import org.objectweb.asm.tree.VarInsnNode; 029 030 /** Differentiation transformer for DRETURN instructions. 031 * <p>DRETURN instructions are replaced by instructions 032 * that build a {@link org.apache.commons.nabla.core.DifferentialPair 033 * DifferentialPair} instance from the expanded differential pair 034 * on operand stack head and an ARETURN instruction returning this 035 * instance.</p> 036 */ 037 public class DReturnTransformer implements InstructionsTransformer { 038 039 // CHECKSTYLE: stop HideUtilityClassConstructor 040 /** Holder for the singleton instance.*/ 041 private static class LazyHolder { 042 /** The singleton instance. */ 043 private static final InstructionsTransformer INSTANCE = new DReturnTransformer(); 044 } 045 // CHECKSTYLE: resume HideUtilityClassConstructor 046 047 /** Hidden constructor. 048 */ 049 private DReturnTransformer() { 050 } 051 052 /** Get the singleton instance. 053 * <p>We use here the Initialization on Demand Holder idiom.</p> 054 * @return the singleton instance 055 */ 056 public static InstructionsTransformer getInstance() { 057 return LazyHolder.INSTANCE; 058 } 059 060 /** {@inheritDoc} */ 061 public InsnList getReplacement(final AbstractInsnNode insn, 062 final MethodDifferentiator methodDifferentiator) 063 throws DifferentiationException { 064 065 // reuse local variables slots 1, 2, 3 and 4 for temporary storage 066 // (this may reduce the number of needed local variables) 067 methodDifferentiator.useLocal(1, 4); 068 069 final InsnList list = new InsnList(); 070 // operand stack initial state: a0, a1 071 list.add(new VarInsnNode(Opcodes.DSTORE, 3)); // => a0 072 list.add(new VarInsnNode(Opcodes.DSTORE, 1)); // => 073 list.add(new TypeInsnNode(Opcodes.NEW, 074 MethodDifferentiator.DP_NAME)); // => o, 075 list.add(new InsnNode(Opcodes.DUP)); // => o, o 076 list.add(new VarInsnNode(Opcodes.DLOAD, 1)); // => o, o, a0 077 list.add(new VarInsnNode(Opcodes.DLOAD, 3)); // => o, o, a0, a1 078 list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, 079 MethodDifferentiator.DP_NAME, 080 "<init>", "(DD)V")); // => dp 081 list.add(new InsnNode(Opcodes.ARETURN)); // => 082 return list; 083 084 } 085 086 }