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

Java tutorial

Introduction

Here is the source code for org.formulacompiler.compiler.internal.bytecode.ClassCompiler.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.Map;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

abstract class ClassCompiler {
    private final ByteCodeEngineCompiler engineCompiler;
    private final boolean classPublic;
    private final String className;
    private final String classInternalName;
    private final String classDescriptor;
    private final Type classType;
    private final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    public ClassCompiler(ByteCodeEngineCompiler _compiler, String _className, boolean _public) {
        super();
        this.engineCompiler = _compiler;
        this.classPublic = _public;
        this.className = _className;
        this.classInternalName = ByteCodeEngineCompiler.GEN_PACKAGE_PATH + this.className;
        this.classDescriptor = "L" + this.classInternalName + ";";
        this.classType = Type.getType(this.classDescriptor);
    }

    final ByteCodeEngineCompiler engineCompiler() {
        return this.engineCompiler;
    }

    final String classInternalName() {
        return this.classInternalName;
    }

    final String classDescriptor() {
        return this.classDescriptor;
    }

    final String className() {
        return this.className;
    }

    final Type classType() {
        return this.classType;
    }

    final ClassWriter cw() {
        return this.cw;
    }

    protected Type initializeClass(Class _parentClassOrInterface, Type _parentTypeOrInterface,
            Type _otherInterface) {
        final Type parentType;
        final String[] interfaces;
        if (_parentClassOrInterface == null) {
            parentType = Type.getType(Object.class);
            interfaces = new String[] { _otherInterface.getInternalName() };
        } else if (_parentClassOrInterface.isInterface()) {
            parentType = Type.getType(Object.class);
            interfaces = new String[] { _otherInterface.getInternalName(),
                    _parentTypeOrInterface.getInternalName() };
        } else {
            parentType = _parentTypeOrInterface;
            interfaces = new String[] { _otherInterface.getInternalName() };
        }
        final int access = Opcodes.ACC_FINAL | (this.classPublic ? Opcodes.ACC_PUBLIC : 0);
        cw().visit(Opcodes.V1_4, access, classInternalName(), null, parentType.getInternalName(), interfaces);

        if (_parentClassOrInterface != null) {
            compileClassRef(_parentClassOrInterface, _parentTypeOrInterface);
        }

        cw().visitSource(null, null);

        return parentType;
    }

    protected void finalizeClass() {
        finalizeStaticInitializer();
        cw().visitEnd();
    }

    GeneratorAdapter newMethod(int _access, String _name, String _descriptor) {
        final MethodVisitor mv = cw().visitMethod(_access, _name, _descriptor, null, null);
        final GeneratorAdapter ma = new GeneratorAdapter(mv, _access, _name, _descriptor);
        ma.visitCode();
        return ma;
    }

    void endMethod(GeneratorAdapter _mv) {
        _mv.endMethod();
        _mv.visitEnd();
    }

    void newField(int _access, String _name, String _descriptor) {
        cw().visitField(_access, _name, _descriptor, null, null).visitEnd();
    }

    public void compileClassRef(Class _class) {
        compileClassRef(_class, Type.getType(_class));
    }

    public void compileClassRef(Class _class, Type _type) {
        if (_class.isMemberClass()) {
            final Class outerClass = _class.getDeclaringClass();
            final Type outerType = Type.getType(outerClass);
            final String innerIntName = _type.getInternalName();
            final String outerIntName = outerType.getInternalName();
            final String innerName = innerIntName.substring(outerIntName.length() + 1);
            cw().visitInnerClass(innerIntName, outerIntName, innerName, _class.getModifiers());
        }
    }

    private GeneratorAdapter initializer;

    protected final GeneratorAdapter initializer() {
        if (this.initializer == null) {
            buildStaticInitializer();
        }
        return this.initializer;
    }

    private void buildStaticInitializer() {
        this.initializer = newMethod(Opcodes.ACC_STATIC, "<clinit>", "()V");
    }

    private void finalizeStaticInitializer() {
        if (this.initializer != null) {
            final GeneratorAdapter ma = this.initializer;
            ma.visitInsn(Opcodes.RETURN);
            endMethod(ma);
            this.initializer = null;
        }
    }

    final byte[] getClassBytes() {
        return cw().toByteArray();
    }

    void collectClassNamesAndBytes(Map<String, byte[]> _result) {
        _result.put(classInternalName().replace('/', '.'), getClassBytes());
    }

}