package org.simantics.scl.compiler.constants; import org.cojen.classfile.TypeDesc; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.internal.codegen.continuations.Cont; import org.simantics.scl.compiler.internal.codegen.references.IVal; import org.simantics.scl.compiler.internal.codegen.references.Val; import org.simantics.scl.compiler.internal.codegen.ssa.statements.LetApply; import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy; import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder; import org.simantics.scl.compiler.internal.codegen.utils.ModuleBuilder; import org.simantics.scl.compiler.internal.codegen.utils.SSASimplificationContext; import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder; import org.simantics.scl.compiler.runtime.MutableClassLoader; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import gnu.trove.map.hash.THashMap; /** * Constant is a subclass of Val that does not need to be * copied when a function is copied. * * @author Hannu Niemistö */ public abstract class Constant extends Val { public static boolean TRACE_REALIZATION = false; protected Type type; public Constant(Type type) { this.type = type; } @Override public Type getType() { return type; } public int getArity() { return 0; } @Override public void push(MethodBuilder mb) { throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support push."); } /** * Deconstructs the parameter and calls continuation with found components. * If the parameter is not constructed with this constructor the execution jumps * to failure. If failure is null, the deconstructor assumes that parameter can * be deconstructed. * @param mb * @param parameter * @param success * @param failure, label where to jump if deconstruct fails. * May be null, if deconstructing cannot fail. */ public void deconstruct(MethodBuilder mb, IVal parameter, Cont success, Label failure) { throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support deconstruct."); } /** * Returns -1, if the constant does not support deconstructing. Otherwise * gives the tag of the constructor. */ public int constructorTag() { return -1; } public void inline(SSASimplificationContext context, LetApply apply) { } @Override public Val copy(THashMap tvarMap) { return this; } @Override public int getEffectiveArity() { return 0; } @Override public Object realizeValue(TransientClassBuilder builder) { THashMap valueCache = builder.classLoader.getConstantCache(); if(valueCache != null) { Object cachedResult = valueCache.get(this); if(cachedResult != null) return cachedResult; } String packageName = builder.classLoader.getFreshPackageName(); String moduleName = packageName + "/Temp"; JavaNamingPolicy policy = new JavaNamingPolicy(moduleName); ModuleBuilder moduleBuilder = new ModuleBuilder(policy, builder.javaTypeTranslator); if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) System.out.println("Create class " + policy.getModuleClassName()); ClassBuilder classFile = new ClassBuilder(moduleBuilder, Opcodes.ACC_PUBLIC, policy.getModuleClassName(), "java/lang/Object"); classFile.setSourceFile("_SCL_RealizedValue"); classFile.addField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "VALUE", TypeDesc.OBJECT); MethodBuilder mb = classFile.addInitializer(); mb.pushBoxed(this); mb.storeStaticField(classFile.getClassName(), "VALUE", TypeDesc.OBJECT); mb.returnVoid(); mb.finish(); moduleBuilder.addClass(classFile); MutableClassLoader classLoader = builder.classLoader; classLoader.addClasses(moduleBuilder.getClasses()); try { Object result = classLoader.loadClass(policy.getModuleClassName().replace('/', '.')).getField("VALUE").get(null); if(valueCache != null) { valueCache.put(this, result); if(TRACE_REALIZATION) System.out.println("/REALIZED/ " + this + " " + getClass().getSimpleName()); } return result; } catch (IllegalAccessException e) { throw new InternalCompilerError(e); } catch (ClassNotFoundException e) { throw new InternalCompilerError(e); } catch (IllegalArgumentException e) { throw new InternalCompilerError(e); } catch (SecurityException e) { throw new InternalCompilerError(e); } catch (NoSuchFieldException e) { throw new InternalCompilerError(e); } } }