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

Java tutorial

Introduction

Here is the source code for org.formulacompiler.compiler.internal.bytecode.SubSectionCompiler.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 static org.formulacompiler.compiler.internal.bytecode.ByteCodeEngineCompiler.*;

import org.formulacompiler.compiler.CompilerException;
import org.formulacompiler.compiler.internal.model.SectionModel;
import org.formulacompiler.runtime.spreadsheet.RangeAddress;
import org.formulacompiler.runtime.spreadsheet.CellAddress;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

final class SubSectionCompiler extends SectionCompiler {
    private final SectionCompiler parentSectionCompiler;
    private final String arrayDescriptor;
    private final Type arrayType;
    private final String getterName;
    private final String getterDescriptor;

    SubSectionCompiler(SectionCompiler _parent, SectionModel _model, boolean _computationListenerEnabled) {
        super(_parent.engineCompiler(), _model, _parent.engineCompiler().newSubClassName(),
                _computationListenerEnabled);
        this.parentSectionCompiler = _parent;
        this.arrayDescriptor = "[" + classDescriptor();
        this.arrayType = Type.getType(arrayDescriptor());
        this.getterName = "get" + className();
        this.getterDescriptor = "()" + arrayDescriptor();
        _parent.addSubSectionCompiler(_model, this);
    }

    @Override
    protected SectionCompiler parentSectionCompiler() {
        return this.parentSectionCompiler;
    }

    @Override
    protected RootSectionCompiler rootSectionCompiler() {
        return parentSectionCompiler().rootSectionCompiler();
    }

    String arrayDescriptor() {
        return this.arrayDescriptor;
    }

    Type arrayType() {
        return this.arrayType;
    }

    String getterName() {
        return this.getterName;
    }

    String getterDescriptor() {
        return this.getterDescriptor;
    }

    private Type parentType() {
        return parentSectionCompiler().classType();
    }

    private Type rootType() {
        return rootSectionCompiler().classType();
    }

    @Override
    protected void buildMembers() {
        super.buildMembers();
        buildParentMember();
        buildRootMember();
        if (this.isComputationListenerEnabled())
            buildIndex();
    }

    private void buildParentMember() {
        // Package visible so subsections can read it.
        newField(Opcodes.ACC_FINAL, PARENT_MEMBER_NAME, parentType().getDescriptor());
    }

    private void buildRootMember() {
        // Package visible so subsections can read it.
        newField(Opcodes.ACC_FINAL, ROOT_MEMBER_NAME, rootType().getDescriptor());
    }

    private void buildIndex() {
        newField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, INDEX_MEMBER_NAME, INDEX_TYPE.getDescriptor());
    }

    @Override
    protected void buildConstructorWithInputs() throws CompilerException {
        final StringBuilder descriptor = new StringBuilder("(");
        descriptor.append(inputType().getDescriptor());
        descriptor.append(parentType().getDescriptor());
        if (this.isComputationListenerEnabled())
            descriptor.append(INDEX_TYPE.getDescriptor());
        descriptor.append(")V");

        final MethodCompiler constructorCompiler = new MethodCompiler(this, 0, "<init>", descriptor.toString()) {
            @Override
            protected void compileBody() throws CompilerException {
                final GeneratorAdapter mv = mv();

                // super( _inputs ); or super(); or super( _inputs, _parent );
                callInheritedConstructor(mv, 1);

                // this.parent = _parent;
                mv.loadThis();
                mv.loadArg(1);
                mv.putField(classType(), PARENT_MEMBER_NAME, parentType());
                // this.root = _parent.root();
                mv.loadThis();
                mv.loadArg(1);
                final Type rootType = rootSectionCompiler().classType();
                if (!(parentSectionCompiler() instanceof RootSectionCompiler)) {
                    // parent.root is package visible
                    mv.getField(parentType(), ROOT_MEMBER_NAME, rootType);
                }
                mv.putField(SubSectionCompiler.this.classType(), ROOT_MEMBER_NAME, rootType);

                // this.inputs = _inputs;
                if (hasInputs()) {
                    mv.loadThis();
                    mv.loadArg(0);
                    storeInputs(mv);
                }

                //this.sectionInfo = new SectionInfoImpl(...);
                if (isComputationListenerEnabled()) {
                    mv.loadThis();
                    mv.loadArg(2); //section index
                    final ExpressionCompilerForNumbers c = numericCompiler();
                    final SectionModel sectionModel = model();
                    final RangeAddress range = (RangeAddress) model().getSource();
                    final CellAddress topLeft = range.getTopLeft();
                    final CellAddress bottomRight = range.getBottomRight();
                    c.compile_util_createSectionInfo(sectionModel.getName(), topLeft.getSheetName(),
                            topLeft.getRowIndex(), topLeft.getColumnIndex(), bottomRight.getSheetName(),
                            bottomRight.getRowIndex(), bottomRight.getColumnIndex());
                    mv.putField(section().classType(), SECTION_INFO_MEMBER_NAME, SECTION_INFO_CLASS);
                }

                mv.visitInsn(Opcodes.RETURN);
            }
        };
        constructorCompiler.compile();
    }

    @Override
    protected void finalizeConstructor() throws CompilerException {
        // Finalized already.
    }

    @Override
    protected boolean callConstructorWithInputs(GeneratorAdapter _mv, int _inputsVar) {
        final int P_PARENT = 2;

        // try super( _inputs, _parent );
        try {
            // ensure it is here and accessible
            outputClass().getConstructor(inputClass(), parentSectionCompiler().model().getOutputClass());
        } catch (NoSuchMethodException e) {
            return super.callConstructorWithInputs(_mv, _inputsVar);
        }

        _mv.loadThis();
        if (0 <= _inputsVar) {
            _mv.visitVarInsn(Opcodes.ALOAD, _inputsVar);
        } else {
            _mv.visitInsn(Opcodes.ACONST_NULL);
        }
        _mv.visitVarInsn(Opcodes.ALOAD, P_PARENT);
        _mv.visitMethodInsn(Opcodes.INVOKESPECIAL, outputType().getInternalName(), "<init>",
                "(" + inputType().getDescriptor() + parentSectionCompiler().outputType().getDescriptor() + ")V");

        return true;
    }

    @Override
    protected void compileEnvironmentAccess(GeneratorAdapter _mv) {
        final Type rootType = rootType();
        _mv.loadThis();
        _mv.getField(classType(), ROOT_MEMBER_NAME, rootType);
        _mv.getField(rootType, ENV_MEMBER_NAME, ENV_CLASS);
    }

    @Override
    protected void compileComputationModeAccess(final GeneratorAdapter _mv) {
        final Type rootType = rootType();
        _mv.loadThis();
        _mv.getField(classType(), ROOT_MEMBER_NAME, rootType);
        rootSectionCompiler().compileComputationModeAccessGivenThis(_mv);
    }

    @Override
    protected void compileComputationTimeAccess(GeneratorAdapter _mv) {
        final Type rootType = rootType();
        _mv.loadThis();
        _mv.getField(classType(), ROOT_MEMBER_NAME, rootType);
        rootSectionCompiler().compileComputationTimeAccessGivenThis(_mv);
    }

}