org.formulacompiler.compiler.internal.bytecode.SubSectionOutputAccessorCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.formulacompiler.compiler.internal.bytecode.SubSectionOutputAccessorCompiler.java

Source

/*
 * Copyright (c) 2006-2009 by Abacus Research AG, Switzerland.
 * All rights reserved.
 *
 * This file is part of the Abacus Formula Compiler (AFC).
 *
 * For commercial licensing, please contact sales(at)formulacompiler.com.
 *
 * AFC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * AFC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with AFC.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.formulacompiler.compiler.internal.bytecode;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.formulacompiler.compiler.CallFrame;
import org.formulacompiler.compiler.CompilerException;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

final class SubSectionOutputAccessorCompiler extends MethodCompiler {
    private static final Type ITERATOR_INTF = Type.getType(Iterator.class);
    private static final Type ARRAYLIST_CLASS = Type.getType(ArrayList.class);

    private final SubSectionCompiler sub;
    private final CallFrame callToImplement;

    SubSectionOutputAccessorCompiler(SectionCompiler _section, SubSectionCompiler _sub,
            CallFrame _callToImplement) {
        super(_section, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, _callToImplement.getMethod().getName(),
                Type.getMethodDescriptor(_callToImplement.getMethod()));
        this.sub = _sub;
        this.callToImplement = _callToImplement;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void compileBody() throws CompilerException {
        final SubSectionCompiler sub = this.sub;
        final GeneratorAdapter mv = mv();

        final CallFrame outputCall = this.callToImplement;
        final Class outputContainerClass = outputCall.getMethod().getReturnType();

        // get$Sect0()
        mv.loadThis();
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, section().classInternalName(), sub.getterName(),
                sub.getterDescriptor());

        if (outputContainerClass.isArray()) {
            mv.visitInsn(Opcodes.ARETURN);
        } else {
            // Detail[] arr = get$Sect0();
            final int l_arr = mv.newLocal(sub.arrayType());
            mv.storeLocal(l_arr);

            final int l_len = mv.newLocal(Type.INT_TYPE);
            mv.loadLocal(l_arr);
            mv.arrayLength();
            mv.storeLocal(l_len);

            // List lst = new ArrayList( arr.length );
            final int l_lst = mv.newLocal(ARRAYLIST_CLASS);
            mv.newInstance(ARRAYLIST_CLASS);
            mv.dup();
            mv.loadLocal(l_len);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, ARRAYLIST_CLASS.getInternalName(), "<init>", "(I)V");
            mv.storeLocal(l_lst);

            // for (int i = 0; i < len; i++) {
            final int l_i = mv.newLocal(Type.INT_TYPE);
            mv.push(0);
            mv.storeLocal(l_i);
            final Label test = mv.newLabel();
            mv.goTo(test);
            final Label again = mv.mark();

            // lst.add( arr[ i ] );
            mv.loadLocal(l_lst);
            mv.loadLocal(l_arr);
            mv.loadLocal(l_i);
            mv.arrayLoad(sub.classType());
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ARRAYLIST_CLASS.getInternalName(), "add",
                    "(Ljava/lang/Object;)Z");
            mv.pop();

            // } // for
            mv.iinc(l_i, 1);
            mv.mark(test);
            mv.loadLocal(l_i);
            mv.loadLocal(l_len);
            mv.ifCmp(Type.INT_TYPE, mv.LT, again);

            mv.loadLocal(l_lst);
            if (outputContainerClass.isAssignableFrom(List.class)) {
                // return lst;
                mv.visitInsn(Opcodes.ARETURN);
            } else if (outputContainerClass.isAssignableFrom(Iterator.class)) {
                // return lst.iterator();
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ARRAYLIST_CLASS.getInternalName(), "iterator",
                        "()" + ITERATOR_INTF.getDescriptor());
                mv.visitInsn(Opcodes.ARETURN);
            } else {
                throw new CompilerException.UnsupportedDataType("The return type of '" + outputCall.getMethod()
                        + "' is not supported as input to a repeating section.");
            }
        }
    }

}