Java tutorial
/* * Copyright (c) 2013-2014 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package edu.mit.streamjit.util.bytecode; import static com.google.common.base.Preconditions.*; import com.google.common.base.Strings; import com.google.common.collect.Iterables; import edu.mit.streamjit.util.bytecode.types.Type; import edu.mit.streamjit.util.bytecode.types.TypeFactory; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Writer; import java.lang.reflect.Array; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Module is the top-level IR node for a single compilation, analogous to a * translation unit in other compilers. * @author Jeffrey Bosboom <jbosboom@csail.mit.edu> * @since 3/6/2013 */ public final class Module { private final TypeFactory typeFactory = new TypeFactory(this); private final ConstantFactory constantFactory = new ConstantFactory(this); private final KlassList klasses = new KlassList(this); private final Map<String, Klass> klassesMap = new HashMap<>(); public Module() { } public List<Klass> klasses() { return klasses; } public TypeFactory types() { return typeFactory; } public ConstantFactory constants() { return constantFactory; } /** * Gets the Klass with the given name, or null if this Module doesn't * contain a Klass with the given name. * @param name the name of the Klass to get * @return the Klass with the given name, or null */ public Klass getKlass(String name) { checkNotNull(name); return klassesMap.get(name); } /** * Gets the Klass representing the given Class object, creating and adding * it to this module if necessary. * @param klass the class to get a Klass for * @return a Klass representing the given Class */ public Klass getKlass(Class<?> klass) { Klass klassByName = getKlass(klass.getName()); if (klassByName != null) return klassByName; return new Klass(klass, this); } public Klass getArrayKlass(Klass componentType, int dimensions) { checkNotNull(componentType); checkArgument(dimensions >= 1); if (componentType.getBackingClass() != null) return getKlass(Array.newInstance(componentType.getBackingClass(), new int[dimensions]).getClass()); StringBuilder nameBuilder = new StringBuilder(Strings.repeat("[", dimensions)); //Always a reference type; if not already an array, add L and ;. nameBuilder.append(componentType.isArray() ? componentType.getName() : "L" + componentType.getName() + ";"); String name = nameBuilder.toString(); Klass alreadyExists = getKlass(name); if (alreadyExists != null) return alreadyExists; return new Klass(componentType, dimensions, this); } public void dump(OutputStream stream) { dump(new PrintWriter(new OutputStreamWriter(stream, StandardCharsets.UTF_8))); } public void dump(Writer writer) { dump(new PrintWriter(writer)); } public void dump(PrintWriter writer) { writer.write("module " + toString()); writer.println(); List<Klass> mutable = new ArrayList<>(), immutable = new ArrayList<>(); for (Klass k : klasses) if (k.isMutable()) mutable.add(k); else immutable.add(k); writer.write(mutable.size() + " mutable klasses"); writer.println(); for (Klass k : mutable) { k.dump(writer); writer.println(); } writer.write(immutable.size() + " immutable klasses"); writer.println(); for (Klass k : immutable) { //For brevity, just print names. writer.write(k.getName()); writer.println(); } writer.println(); writer.write(Iterables.size(types()) + " types"); writer.println(); for (Type t : types()) { writer.write(t.toString()); writer.println(); } writer.println(); writer.write(Iterables.size(constants()) + " constants"); writer.println(); for (Constant<?> c : constants()) { writer.write(c.toString()); writer.println(); } } /** * Ensures we don't end up with two classes with the same name in the list. */ private class KlassList extends ParentedList<Module, Klass> { private KlassList(Module parent) { super(parent, Klass.class); } @Override protected void elementAdding(Klass t) { checkArgument(!klassesMap.containsKey(t.getName()), "adding duplicate %s", t.getName()); super.elementAdding(t); } @Override protected void elementAdded(Klass t) { super.elementAdded(t); klassesMap.put(t.getName(), t); } @Override protected void elementRemoving(Klass t) { //Removing an immutable Klass makes no sense as any replacement //would have no effect (because the module-based ClassLoader prefers //classes loaded by the parent) and could break other mutable //Klasses if they depended on the changed definitions. checkArgument(t.isMutable(), "removing immutable Klass %s", t.getName()); super.elementRemoving(t); } @Override protected void elementRemoved(Klass t) { super.elementRemoved(t); Klass removed = klassesMap.remove(t.getName()); assert t.equals(removed) : t + ", " + removed; } } }