package org.simantics.scl.compiler.constants; import org.cojen.classfile.TypeDesc; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.internal.codegen.references.Val; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; public class JavaStaticMethod extends FunctionValue { String className; String methodName; TypeDesc returnTypeDesc; TypeDesc[] parameterTypeDescs; public JavaStaticMethod(String className, String methodName, Type effect, TVar[] typeParameters, Type returnType, Type ... parameterTypes) { super(typeParameters, effect, returnType, parameterTypes); if(SCLCompilerConfiguration.DEBUG) { if(className.contains("/")) throw new InternalCompilerError(); } ClassBuilder.checkClassName(className); this.className = className; this.methodName = methodName; } public JavaStaticMethod(String className, String methodName, Type effect, Type returnType, Type ... parameterTypes) { super(Types.freeVarsArray(Types.functionE(parameterTypes, effect, returnType)), effect, returnType, parameterTypes); if(SCLCompilerConfiguration.DEBUG) { if(className.contains("/")) throw new InternalCompilerError(); } ClassBuilder.checkClassName(className); this.className = className; this.methodName = methodName; } public JavaStaticMethod(String className, String methodName, Type effect, TypeDesc returnTypeDesc, TypeDesc[] parameterTypeDescs, Type returnType, Type ... parameterTypes) { super(Types.freeVarsArray(Types.functionE(parameterTypes, effect, returnType)), effect, returnType, parameterTypes); if(SCLCompilerConfiguration.DEBUG) { if(className == null) throw new NullPointerException(); if(methodName == null) throw new NullPointerException(); if(parameterTypeDescs != null) for(TypeDesc td : parameterTypeDescs) if(td.equals(TypeDesc.VOID)) throw new InternalCompilerError(); } if( (returnTypeDesc == null) != (parameterTypeDescs == null) ) throw new IllegalArgumentException("Either specify both returnTypeDesc and parameterTypeDescs or neither"); ClassBuilder.checkClassName(className); this.className = className; this.methodName = methodName; this.returnTypeDesc = returnTypeDesc; this.parameterTypeDescs = parameterTypeDescs; } public JavaStaticMethod(String className, String methodName, TypeDesc returnTypeDesc, TypeDesc[] parameterTypeDescs, Type returnType, Type ... parameterTypes) { this(className, methodName, Types.NO_EFFECTS, returnTypeDesc, parameterTypeDescs, returnType, parameterTypes); } @Override public Type applyExact(MethodBuilder mb, Val[] parameters) { if(returnTypeDesc == null || parameterTypeDescs == null) { // This method may be called from multiple threads at the same time when returnTypeDesc // and parameterTypeDescs are uninitialized. Double initialization is OK in this case, // but because there are two fields, we have to check that both are initialized. JavaTypeTranslator tt = mb.getJavaTypeTranslator(); returnTypeDesc = tt.toTypeDesc(returnType); parameterTypeDescs = JavaTypeTranslator.filterVoid( tt.toTypeDescs(parameterTypes)); } mb.push(parameters, getParameterTypes()); mb.invokeStatic(className, methodName, returnTypeDesc, parameterTypeDescs); return getReturnType(); } @Override public String toString() { return className + "#" + methodName; } }