1 package org.simantics.scl.compiler.runtime;
5 import org.simantics.scl.compiler.constants.Constant;
7 import gnu.trove.map.hash.THashMap;
9 public class ExpressionClassLoader extends ClassLoader implements MutableClassLoader {
10 public static final boolean VALIDATE_CLASS_NAMES = true;
11 public static final boolean TRACE_CLASS_CREATION = false;
13 String basePackageName;
14 public THashMap<String, byte[]> localClasses = new THashMap<String, byte[]>();
15 THashMap<String, RuntimeModule> runtimeModuleMap;
16 int transientPackageId = 0;
17 THashMap<Constant,Object> valueCache = new THashMap<Constant,Object>();
19 public ExpressionClassLoader(ClassLoader parent, THashMap<String, RuntimeModule> runtimeModuleMap, String basePackageName) {
21 this.basePackageName = basePackageName;
22 this.runtimeModuleMap = runtimeModuleMap;
25 public synchronized void addClass(String name, byte[] class_) {
26 if(TRACE_CLASS_CREATION)
27 System.out.println("addClass " + name + " (" + class_.length + " bytes)");
28 if(VALIDATE_CLASS_NAMES)
29 validateClassName(name);
30 localClasses.put(name, class_);
33 public synchronized void addClasses(Map<String, byte[]> classes) {
34 if(TRACE_CLASS_CREATION)
35 for(String name : classes.keySet())
36 System.out.println("addClass " + name + " (" + classes.get(name).length + " bytes)");
37 if(VALIDATE_CLASS_NAMES)
38 for(String name : classes.keySet())
39 validateClassName(name);
40 localClasses.putAll(classes);
43 private void validateClassName(String name) {
44 /*if(!name.startsWith(SCL_PACKAGE_PREFIX) || !extractClassLoaderId(name).equals(basePackageName))
45 throw new IllegalArgumentException("Class name " + name + " does not start with '" +
46 SCL_PACKAGE_PREFIX + basePackageName + "$'.");*/
49 private synchronized Class<?> getLocalClass(String name) throws ClassNotFoundException {
50 // Is class already loaded
51 Class<?> clazz = findLoadedClass(name);
55 // If we have bytecode for it, let's define the class
56 byte[] bytes = localClasses.get(name.replace('.', '/'));
58 throw new ClassNotFoundException(name);
60 clazz = defineClass(name, bytes, 0, bytes.length);
68 public byte[] getBytes(String name) {
69 // Non-SCL classes are not handled here
70 if(!name.startsWith(SCL_PACKAGE_PREFIX))
73 // Determine the id of the class loader which is responsible of the class
74 String requestedModuleName = RuntimeModule.extractClassLoaderId(name);
76 // Is class defined locally in this class loader?
77 if(requestedModuleName.equals(basePackageName)) {
78 String internalName = name.replace('.', '/');
79 byte[] bytes = localClasses.get(internalName);
82 return localClasses.get(internalName);
85 // Find suitable class loader that has this class locally
87 RuntimeModule parentModule = runtimeModuleMap.get(requestedModuleName);
88 if(parentModule == null)
91 // Find the class from the ancestor class loader
92 return parentModule.classLoader.getBytes(name);
96 private Class<?> getClass(String name) throws ClassNotFoundException {
97 //System.out.println("getClass " + name);
99 // If the class is not generated from SCL, use parent class loader
100 if(!name.startsWith(SCL_PACKAGE_PREFIX)) {
102 return getParent().loadClass(name);
103 } catch(ClassNotFoundException e) {
104 for(RuntimeModule module : runtimeModuleMap.values())
106 return module.classLoader.getParent().loadClass(name);
107 } catch(ClassNotFoundException e2) {
110 throw new ClassNotFoundException(name);
113 // Determine the id of the class loader which is responsible of the class
114 String requestedModuleName = RuntimeModule.extractClassLoaderId(name);
116 // Is class defined locally in this class loader?
117 if(requestedModuleName.equals(basePackageName))
118 return getLocalClass(name);
120 // Find suitable class loader that has this class locally
122 RuntimeModule parentModule = runtimeModuleMap.get(requestedModuleName);
123 if(parentModule == null)
124 throw new ClassNotFoundException(name);
126 // Find the class from the ancestor class loader
127 return parentModule.classLoader.getLocalClass(name);
132 public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
133 Class<?> clazz = getClass(name);
139 public synchronized String getFreshPackageName() {
140 return basePackageName + "$" + (++transientPackageId);
144 public THashMap<Constant, Object> getConstantCache() {
149 public ClassLoader getClassLoader() {