/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Program.java * Creation date: (March 17 2000 10:34:54 AM) * By: LWE */ package org.openquark.cal.machine; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.openquark.cal.compiler.ModuleName; import org.openquark.cal.compiler.QualifiedName; import org.openquark.cal.runtime.ExecutionContext; /** * Warning- this class should only be used by the CAL runtime implementation. It is not part of the * external API of the CAL platform. * <P> * A Program is a collection of one or more modules which have been loaded to * define an executable program. * * @author LWE, Raymond Cypher */ public abstract class Program { private final Map<ModuleName, Module> moduleNameToModuleMap; /** Mapping from module name to timestamp of last successful compilation */ private Map<ModuleName, Long> compiledModuleTimestamps = new HashMap<ModuleName, Long>(); /** Whether or not to use the CAL optimizer when compiling the program */ private boolean useOptimizer = true; //--------------------------------------------------------------------------------- // NOTE: if additional data structures are added to the Program, make sure that // that they are cleaned up appropriately when a module is removed from the Program //--------------------------------------------------------------------------------- //private Object machineSpecificInfo; /** * Default constructor */ public Program () { moduleNameToModuleMap = new HashMap<ModuleName, Module>(); } /** * Add a module to this program. * Normally called by a Loader. * Derived Program classes create a type-specific module object and then call addModule (Module) * @param moduleName * @param foreignClassLoader the classloader to use to resolve foreign classes for the module. * @return the newly created Module */ public abstract Module addModule(ModuleName moduleName, ClassLoader foreignClassLoader); /** * Add the given module to this program. * @param module */ synchronized public void addModule (Module module) { moduleNameToModuleMap.put(module.getName(), module); } /** * @param name - the QualifiedName of the function to retrieve information about * @return - the MachineFunction object associated with the named function, may be null * @throws ProgramException */ synchronized public final MachineFunction getCodeLabel (QualifiedName name) throws ProgramException { // Get the module object matching the module name Module thisModule = moduleNameToModuleMap.get(name.getModuleName()); if (thisModule == null) { // No module throw new Program.ProgramException("Unable to resolve module in label: " + name); } MachineFunction cl = thisModule.getFunction(name.getUnqualifiedName()); return cl; } /** * Return an array of module names for the modules in this program. * @return an array of module names for the modules in this program. */ synchronized public final ModuleName[] getModuleNames() { return moduleNameToModuleMap.keySet().toArray(new ModuleName[0]); } /** * Return a <b>copy</b> of the modules in this program.. * * @return a copy of the modules in this program in a new Collection object. */ synchronized public final List<Module> getModules () { /* * THREAD-SAFETY ISSUE: * this needs to be a copy, and not an unmodifiable view based on the underlying * collection (e.g. via Collections.unmodifiableCollection()), because iterating through * such a list is incompatible with concurrent modification (it would result in a * java.util.ConcurrentModificationException). Such a scenario will occur * with compilations taking place simultaneously on multiple threads. */ return new ArrayList<Module>(moduleNameToModuleMap.values()); } /** * Sets whether or not the CAL based optimizer will be use during compilation. * * @param useOptimizer True if the CAL based optimized should be used during compilation. */ public void useOptimizer(boolean useOptimizer){ this.useOptimizer = useOptimizer; } /** * Use this to determine if the CAL based optimizer should be run during compilation. * * @return True iff the CAL based optimizer should be run during compilation. */ public boolean useOptimizer(){ return useOptimizer; } /** * Gets the module with a given moduleName. * @return the module with a given module name * @param moduleName the module name */ synchronized public final Module getModule(ModuleName moduleName) { // Get the module object with the given the module name return moduleNameToModuleMap.get(moduleName); } /** * Remove a named module from this program. * @param moduleName the module to remove * @param includeDependents * @return the Set of modules which were removed */ synchronized public final Set<Module> removeModule(final ModuleName moduleName, final boolean includeDependents) { Set<Module> removedModules = new HashSet<Module>(); { Module module = moduleNameToModuleMap.remove(moduleName); compiledModuleTimestamps.remove(moduleName); if (module != null) { removedModules.add(module); } } if (includeDependents) { Set<ModuleName> dependents = getDependentModules(moduleName); for (final ModuleName dependentName : dependents) { Module dependentModule = moduleNameToModuleMap.remove(dependentName); compiledModuleTimestamps.remove(dependentName); if (dependentModule != null) { removedModules.add(dependentModule); } } } return removedModules; } /** * Generate a set of all modules that depend on the named module * either directly or indirectly. * @param dependeeModuleName The name of the dependee module. * @return Set (of String) A set of names of all dependent modules. */ synchronized public final Set<ModuleName> getDependentModules(ModuleName dependeeModuleName) { Set<ModuleName> v = new HashSet<ModuleName>(); v.add (dependeeModuleName); return getDependentModules(v); } /** * Generate a list of all modules that depend on the named modules * either directly or indirectly. * @param changedModules A Set of names (ModuleName) of modules. * @return A Set of names (ModuleName) of all dependent modules. */ synchronized public final Set<ModuleName> getDependentModules(Set<ModuleName> changedModules) { if (changedModules.isEmpty()) { return Collections.<ModuleName>emptySet(); } Set<ModuleName> v = new HashSet<ModuleName>(); for (final ModuleName moduleName : changedModules) { for (final Module m : moduleNameToModuleMap.values()) { if (m.dependsOn(moduleName) && !v.contains(m.getName()) && !changedModules.contains (m.getName())) { v.add (m.getName()); } } } if (v.isEmpty ()) { return v; } Set<ModuleName> l = getDependentModules(v); for (final ModuleName s : l) { if (!v.contains (s)) { v.add (s); } } return v; } /** * Put an entry into the mapping from module source to the timestamp of last * successful compilation. * * @param moduleName * the module name * @param timestamp * the timestamp of the last successful compilation of the module. Cannot be null. */ synchronized public final void putCompilationTimestamp(ModuleName moduleName, Long timestamp) { if (timestamp == null) { throw new IllegalArgumentException("timestamp cannot be null"); } compiledModuleTimestamps.put(moduleName, timestamp); } /** * Remove the last successful compilation timestamp associated with a module * source. * * @param moduleName * the module name */ synchronized public final void removeCompilationTimestamp(ModuleName moduleName) { compiledModuleTimestamps.remove(moduleName); } /** * Retrieve the last successful compilation timestamp associated with a * module source. * * @param moduleName * the module name * @return the timestamp of the last successful compilation of the module, * or null if the module has not been compiled previously. */ synchronized public final Long getCompilationTimestamp(ModuleName moduleName) { return compiledModuleTimestamps.get(moduleName); } // Abstract methods to be overridden in machine specific derived classes. /** * Discarded any cached (memoized) results in this program. * @param context the context with which the cached results are associated. */ public abstract void resetCachedResults(ExecutionContext context); /** * Discard any cached (memoized) results in the named module and any dependent modules. * @param moduleName * @param context the context with which the cached results are associated. */ public abstract void resetCachedResults(ModuleName moduleName, ExecutionContext context); /** * Discarded the machine state, including any cached (memoized) results in this program. * @param context the context with which the machine state associated. */ public abstract void resetMachineState(ExecutionContext context); /** * Discard the machine state, including any cached (memoized) results in the named module and any dependent modules. * @param moduleName * @param context the context with which the machine state associated. */ public abstract void resetMachineState(ModuleName moduleName, ExecutionContext context); /** * Program exception */ public static final class ProgramException extends Exception { private static final long serialVersionUID = 3533290083808452134L; /** * Construct from message */ ProgramException(String message) { super(message); } } }