Java tutorial
/* * 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.lang.reflect.Method; import org.formulacompiler.runtime.internal.bytecode.ByteCodeEngine; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; final class FactoryCompiler extends ClassCompiler { private static final String ENV_CONSTRUCTOR_SIG = "(" + ByteCodeEngineCompiler.ENV_DESC + ")V"; private final Class userFactoryClass; private final Method userFactoryMethod; private final Type userFactoryType; private final Class userInputClass; private final Type userInputType; FactoryCompiler(ByteCodeEngineCompiler _compiler, Class _factoryClass, Method _factoryMethod) { super(_compiler, ByteCodeEngine.GEN_FACTORY_NAME, true); this.userFactoryClass = _factoryClass; this.userFactoryMethod = _factoryMethod; this.userFactoryType = (_factoryClass != null) ? Type.getType(_factoryClass) : null; this.userInputClass = engineCompiler().getModel().getInputClass(); this.userInputType = Type.getType(this.userInputClass); } void compile() { final Type parentType = initializeClass(this.userFactoryClass, this.userFactoryType, ByteCodeEngineCompiler.FACTORY_INTF); buildEnvironmentField(); buildDefaultConstructor(parentType); buildComputationFactoryMethod(); if (this.userFactoryMethod != null) { buildUserFactoryMethod(); } finalizeClass(); } private void buildEnvironmentField() { newField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, ByteCodeEngineCompiler.ENV_MEMBER_NAME, ByteCodeEngineCompiler.ENV_DESC); } private void buildDefaultConstructor(Type _parentType) { final GeneratorAdapter mv = newMethod(Opcodes.ACC_PUBLIC, "<init>", ENV_CONSTRUCTOR_SIG); mv.visitCode(); mv.loadThis(); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, _parentType.getInternalName(), "<init>", "()V"); mv.loadThis(); mv.loadArg(0); mv.putField(this.classType(), ByteCodeEngineCompiler.ENV_MEMBER_NAME, ByteCodeEngineCompiler.ENV_CLASS); mv.visitInsn(Opcodes.RETURN); endMethod(mv); } private void buildComputationFactoryMethod() { final GeneratorAdapter mv = newMethod("newComputation", "(Ljava/lang/Object;)" + ByteCodeEngineCompiler.COMPUTATION_INTF.getDescriptor()); mv.newInstance(ByteCodeEngineCompiler.GEN_ROOT_CLASS); mv.dup(); mv.loadArg(0); compileClassRef(this.userInputClass, this.userInputType); mv.checkCast(this.userInputType); mv.loadThis(); mv.getField(classType(), ByteCodeEngineCompiler.ENV_MEMBER_NAME, ByteCodeEngineCompiler.ENV_CLASS); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, ByteCodeEngineCompiler.GEN_ROOT_CLASS.getInternalName(), "<init>", "(" + this.userInputType.getDescriptor() + ByteCodeEngineCompiler.ENV_DESC + ")V"); mv.visitInsn(Opcodes.ARETURN); endMethod(mv); } private void buildUserFactoryMethod() { final GeneratorAdapter mv = newMethod(this.userFactoryMethod.getName(), Type.getMethodDescriptor(this.userFactoryMethod)); mv.newInstance(ByteCodeEngineCompiler.GEN_ROOT_CLASS); mv.dup(); mv.loadArg(0); mv.loadThis(); mv.getField(classType(), ByteCodeEngineCompiler.ENV_MEMBER_NAME, ByteCodeEngineCompiler.ENV_CLASS); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, ByteCodeEngineCompiler.GEN_ROOT_CLASS.getInternalName(), "<init>", "(" + this.userInputType.getDescriptor() + ByteCodeEngineCompiler.ENV_DESC + ")V"); mv.visitInsn(Opcodes.ARETURN); endMethod(mv); } private GeneratorAdapter newMethod(String _name, String _signature) { final int access = Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC; return new GeneratorAdapter(cw().visitMethod(access, _name, _signature, null, null), access, _name, _signature); } }