package org.simantics.scl.compiler.internal.codegen.utils; import java.util.Arrays; import java.util.Map; import org.cojen.classfile.TypeDesc; import org.objectweb.asm.Opcodes; import org.simantics.scl.compiler.constants.FunctionValue; import org.simantics.scl.compiler.constants.LocalFieldConstant; import org.simantics.scl.compiler.constants.LocalVariableConstant; import org.simantics.scl.compiler.internal.codegen.references.BoundVar; import org.simantics.scl.compiler.internal.codegen.references.Val; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.types.Type; import gnu.trove.map.hash.THashMap; public class ModuleBuilder { JavaNamingPolicy namingPolicy; JavaTypeTranslator javaTypeTranslator; THashMap classes = new THashMap(); THashMap cache = new THashMap(); MethodSizeCounter methodSizeCounter; public void addClass(ClassBuilder cb) { byte[] bytecode = cb.finishClass(); classes.put(cb.getClassName(), bytecode); //System.out.println("Added " + cb.getClassName()); } public JavaTypeTranslator getJavaTypeTranslator() { return javaTypeTranslator; } static class ClosureDesc { FunctionValue functionValue; int knownParametersCount; public ClosureDesc(FunctionValue functionValue, int knownParametersCount) { this.functionValue = functionValue; this.knownParametersCount = knownParametersCount; } @Override public int hashCode() { return functionValue.hashCode() + 31 * knownParametersCount; } @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null || obj.getClass() != getClass()) return false; ClosureDesc other = (ClosureDesc)obj; return functionValue == other.functionValue && knownParametersCount == other.knownParametersCount; } } public ModuleBuilder(JavaNamingPolicy namingPolicy, JavaTypeTranslator javaTypeTranslator) { this.namingPolicy = namingPolicy; this.javaTypeTranslator = javaTypeTranslator; } public TypeDesc getClosure(FunctionValue functionValue, int knownParametersCount) { ClosureDesc desc = new ClosureDesc(functionValue, knownParametersCount); TypeDesc result = cache.get(desc); if(result == null) { result = createClosure(functionValue, knownParametersCount); cache.put(desc, result); } return result; } private TypeDesc createClosure(FunctionValue functionValue, int knownParametersCount) { String className = namingPolicy.getFreshClosureClassName(); int remainingArity = functionValue.getArity() - knownParametersCount; TypeDesc[] parameterTypes = javaTypeTranslator.toTypeDescs(functionValue.getParameterTypes()); // Create new class ClassBuilder classBuilder; if(remainingArity <= Constants.MAX_FUNCTION_PARAMETER_COUNT) { if(SCLCompilerConfiguration.TRACE_METHOD_CREATION) System.out.println("Create class " + className); classBuilder = new ClassBuilder(this, Opcodes.ACC_PUBLIC, className, MethodBuilderBase.getClassName(Constants.FUNCTION_IMPL[remainingArity])); classBuilder.setSourceFile("_SCL_Closure"); // Create fields CodeBuilderUtils.makeRecord(classBuilder, functionValue.toString(), Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, "p", Arrays.copyOf(parameterTypes, knownParametersCount), true); // Create apply { MethodBuilder mb = classBuilder.addMethod(Opcodes.ACC_PUBLIC, "apply", TypeDesc.OBJECT, Constants.OBJECTS[remainingArity]); Val[] parameters = new Val[functionValue.getArity()]; for(int i=0;i getClasses() { return classes; } public JavaNamingPolicy getNamingPolicy() { return namingPolicy; } public MethodSizeCounter getMethodSizeCounter() { return methodSizeCounter; } }