X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fruntime%2FExpressionClassLoader.java;fp=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Fruntime%2FExpressionClassLoader.java;h=bb2e5efc0a7deb57fc5081c9918a7683f40775c6;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java new file mode 100644 index 000000000..bb2e5efc0 --- /dev/null +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java @@ -0,0 +1,119 @@ +package org.simantics.scl.compiler.runtime; + +import gnu.trove.map.hash.THashMap; + +import java.util.Map; + +import org.simantics.scl.compiler.constants.Constant; + +public class ExpressionClassLoader extends ClassLoader implements MutableClassLoader { + public static final boolean VALIDATE_CLASS_NAMES = true; + public static final boolean TRACE_CLASS_CREATION = false; + + String basePackageName; + THashMap localClasses = new THashMap(); + THashMap runtimeModuleMap; + int transientPackageId = 0; + THashMap valueCache = new THashMap(); + + public ExpressionClassLoader(ClassLoader parent, THashMap runtimeModuleMap, String basePackageName) { + super(parent); + this.basePackageName = basePackageName; + this.runtimeModuleMap = runtimeModuleMap; + } + + public synchronized void addClass(String name, byte[] class_) { + if(TRACE_CLASS_CREATION) + System.out.println("addClass " + name + " (" + class_.length + " bytes)"); + if(VALIDATE_CLASS_NAMES) + validateClassName(name); + localClasses.put(name, class_); + } + + public synchronized void addClasses(Map classes) { + if(TRACE_CLASS_CREATION) + for(String name : classes.keySet()) + System.out.println("addClass " + name + " (" + classes.get(name).length + " bytes)"); + if(VALIDATE_CLASS_NAMES) + for(String name : classes.keySet()) + validateClassName(name); + localClasses.putAll(classes); + } + + private void validateClassName(String name) { + /*if(!name.startsWith(SCL_PACKAGE_PREFIX) || !extractClassLoaderId(name).equals(basePackageName)) + throw new IllegalArgumentException("Class name " + name + " does not start with '" + + SCL_PACKAGE_PREFIX + basePackageName + "$'.");*/ + } + + private synchronized Class getLocalClass(String name) throws ClassNotFoundException { + // Is class already loaded + Class clazz = findLoadedClass(name); + if(clazz != null) + return clazz; + + // If we have bytecode for it, let's define the class + byte[] bytes = localClasses.get(name.replace('.', '/')); + if(bytes == null) + throw new ClassNotFoundException(name); + + return defineClass(name, bytes, 0, bytes.length); + } + + private Class getClass(String name) throws ClassNotFoundException { + //System.out.println("getClass " + name); + + // If the class is not generated from SCL, use parent class loader + if(!name.startsWith(SCL_PACKAGE_PREFIX)) { + try { + return getParent().loadClass(name); + } catch(ClassNotFoundException e) { + for(RuntimeModule module : runtimeModuleMap.values()) + try { + return module.classLoader.getParent().loadClass(name); + } catch(ClassNotFoundException e2) { + } + } + throw new ClassNotFoundException(name); + } + + // Determine the id of the class loader which is responsible of the class + String requestedModuleName = RuntimeModule.extractClassLoaderId(name); + + // Is class defined locally in this class loader? + if(requestedModuleName.equals(basePackageName)) + return getLocalClass(name); + + // Find suitable class loader that has this class locally + else { + RuntimeModule parentModule = runtimeModuleMap.get(requestedModuleName); + if(parentModule == null) + throw new ClassNotFoundException(name); + + // Find the class from the ancestor class loader + return parentModule.classLoader.getLocalClass(name); + } + } + + @Override + public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class clazz = getClass(name); + if (resolve) + resolveClass(clazz); + return clazz; + } + + public synchronized String getFreshPackageName() { + return basePackageName + "$" + (++transientPackageId); + } + + @Override + public THashMap getConstantCache() { + return valueCache; + } + + @Override + public ClassLoader getClassLoader() { + return this; + } +}