org.qbicc.object.ProgramModule Maven / Gradle / Ivy
package org.qbicc.object;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import io.smallrye.common.constraint.Assert;
import org.qbicc.graph.literal.LiteralFactory;
import org.qbicc.type.FunctionType;
import org.qbicc.type.TypeSystem;
import org.qbicc.type.ValueType;
import org.qbicc.type.definition.DefinedTypeDefinition;
import org.qbicc.type.definition.element.ExecutableElement;
import org.qbicc.type.definition.element.MemberElement;
/**
*
*/
public final class ProgramModule {
final DefinedTypeDefinition typeDefinition;
final TypeSystem typeSystem;
final LiteralFactory literalFactory;
// All module objects by name, in no particular order
// protected by this
final Map moduleObjects = new HashMap<>();
// concurrent
final Map sections = new ConcurrentHashMap<>();
// protected by ctors
final List ctors = new ArrayList<>();
// protected by dtors
final List dtors = new ArrayList<>();
public ProgramModule(final DefinedTypeDefinition typeDefinition, final TypeSystem typeSystem, final LiteralFactory literalFactory) {
this.typeDefinition = Assert.checkNotNullParam("typeDefinition", typeDefinition);
this.typeSystem = Assert.checkNotNullParam("typeSystem", typeSystem);
this.literalFactory = Assert.checkNotNullParam("literalFactory", literalFactory);
}
public DefinedTypeDefinition getTypeDefinition() {
return typeDefinition;
}
@Deprecated
public ModuleSection getOrAddSection(String name) {
Section section = typeDefinition.getContext().getCompilationContext().getSection(name);
if (section == null) {
throw new IllegalArgumentException("Section " + name + " is not known");
}
return inSection(section);
}
public Collection sections() {
ModuleSection[] array = this.sections.values().toArray(ModuleSection[]::new);
Arrays.sort(array, Comparator.comparing(ProgramObject::getName));
return List.of(array);
}
public List constructors() {
synchronized (ctors) {
return List.copyOf(ctors);
}
}
public List destructors() {
synchronized (dtors) {
return List.copyOf(dtors);
}
}
public GlobalXtor addConstructor(Function fn, int priority) {
Assert.checkNotNullParam("fn", fn);
Assert.checkMinimumParameter("priority", 0, priority);
GlobalXtor xtor = new GlobalXtor(GlobalXtor.Kind.CTOR, fn, priority);
synchronized (ctors) {
ctors.add(xtor);
}
return xtor;
}
public GlobalXtor addDestructor(Function fn, int priority) {
Assert.checkNotNullParam("fn", fn);
Assert.checkMinimumParameter("priority", 0, priority);
GlobalXtor xtor = new GlobalXtor(GlobalXtor.Kind.DTOR, fn, priority);
synchronized (dtors) {
dtors.add(xtor);
}
return xtor;
}
public ModuleSection inSection(final Section section) {
return sections.computeIfAbsent(Assert.checkNotNullParam("section", section), this::registerSection);
}
/**
* Convenience method to produce a function declaration in this module for the given original program object, which
* must be a function definition or a function declaration.
*
* @param original the original item (must not be {@code null})
* @return the function declaration (not {@code null})
*/
public FunctionDeclaration declareFunction(ProgramObject original) {
if (original instanceof Function fn) {
return declareFunction(fn);
} else if (original instanceof FunctionDeclaration decl) {
return declareFunction(decl);
} else {
throw new IllegalArgumentException("Invalid input type");
}
}
/**
* Convenience method to produce a function declaration in this module for the given original function.
*
* @param originalFunction the original function (must not be {@code null})
* @return the function declaration (not {@code null})
*/
public FunctionDeclaration declareFunction(Function originalFunction) {
Assert.checkNotNullParam("originalFunction", originalFunction);
String name = originalFunction.getName();
Map definedObjects = this.moduleObjects;
synchronized (this) {
ProgramObject existing = definedObjects.get(name);
FunctionDeclaration origDecl = originalFunction.getDeclaration();
if (existing == null) {
definedObjects.put(name, origDecl);
return origDecl;
} else {
if (existing == origDecl) {
// fast/common path
return origDecl;
} else if (existing instanceof FunctionDeclaration decl) {
if (! originalFunction.getSymbolType().equals(decl.getSymbolType())) {
clash(originalFunction.getOriginalElement(), name);
return origDecl;
}
return decl;
} else if (existing instanceof Function fn) {
if (! originalFunction.getSymbolType().equals(fn.getSymbolType())) {
clash(originalFunction.getOriginalElement(), name);
return origDecl;
}
return fn.getDeclaration();
} else {
clash(originalFunction.getOriginalElement(), name);
return origDecl;
}
}
}
}
/**
* Convenience method to produce a function declaration in this module for the given original function declaration.
*
* @param originalDecl the original function declaration (must not be {@code null})
* @return the function declaration (not {@code null})
*/
public FunctionDeclaration declareFunction(FunctionDeclaration originalDecl) {
Assert.checkNotNullParam("originalDecl", originalDecl);
String name = originalDecl.getName();
Map definedObjects = this.moduleObjects;
synchronized (this) {
ProgramObject existing = definedObjects.get(name);
if (existing == null) {
definedObjects.put(name, originalDecl);
return originalDecl;
} else {
if (existing == originalDecl) {
// fast/common path
return originalDecl;
} else if (existing instanceof FunctionDeclaration decl) {
if (! originalDecl.getSymbolType().equals(decl.getSymbolType())) {
clash(originalDecl.getOriginalElement(), name);
return originalDecl;
}
return decl;
} else if (existing instanceof Function fn) {
if (! originalDecl.getSymbolType().equals(fn.getSymbolType())) {
clash(originalDecl.getOriginalElement(), name);
return originalDecl.getDeclaration();
}
return fn.getDeclaration();
} else {
clash(originalDecl.getOriginalElement(), name);
return originalDecl;
}
}
}
}
public FunctionDeclaration declareFunction(ExecutableElement originalElement, String name, FunctionType type) {
return declareFunction(originalElement, name, type, originalElement == null ? 0 : Function.getFunctionFlags(originalElement));
}
public FunctionDeclaration declareFunction(ExecutableElement originalElement, String name, FunctionType type, int flags) {
Assert.checkNotNullParam("name", name);
Map definedObjects = this.moduleObjects;
synchronized (this) {
ProgramObject existing = definedObjects.get(name);
if (existing == null) {
FunctionDeclaration decl = new FunctionDeclaration(originalElement, this, name, type, flags);
definedObjects.put(name, decl);
return decl;
} else {
if (existing instanceof FunctionDeclaration decl) {
if (! type.equals(decl.getValueType())) {
clash(originalElement, name);
return new FunctionDeclaration(originalElement, this, name, type, flags);
}
return decl;
} else if (existing instanceof Function fn) {
if (! type.equals(fn.getValueType())) {
clash(originalElement, name);
return new FunctionDeclaration(originalElement, this, name, type, flags);
}
return fn.getDeclaration();
} else {
clash(originalElement, name);
return new FunctionDeclaration(originalElement, this, name, type, flags);
}
}
}
}
/**
* Convenience method to produce a data declaration in this module for the given original program object, which
* must be a data definition or a data declaration.
*
* @param original the original item (must not be {@code null})
* @return the data declaration (not {@code null})
*/
public DataDeclaration declareData(ProgramObject original) {
if (original instanceof Data data) {
return declareData(data);
} else if (original instanceof DataDeclaration decl) {
return declareData(decl);
} else {
throw new IllegalArgumentException("Invalid input type");
}
}
/**
* Convenience method to produce a data declaration in this module for the given original data definition.
*
* @param originalData the original data definition (must not be {@code null})
* @return the data declaration (not {@code null})
*/
public DataDeclaration declareData(Data originalData) {
Assert.checkNotNullParam("originalData", originalData);
String name = originalData.getName();
Map definedObjects = this.moduleObjects;
synchronized (this) {
ProgramObject existing = definedObjects.get(name);
DataDeclaration origDecl = originalData.getDeclaration();
if (existing == null) {
definedObjects.put(name, origDecl);
return origDecl;
} else {
if (existing == origDecl) {
// fast/common path
return origDecl;
} else if (existing instanceof DataDeclaration decl) {
if (! originalData.getSymbolType().equals(decl.getSymbolType())) {
clash(originalData.getOriginalElement(), name);
return origDecl;
}
return decl;
} else if (existing instanceof Data data) {
if (! originalData.getSymbolType().equals(data.getSymbolType())) {
clash(originalData.getOriginalElement(), name);
return origDecl;
}
return data.getDeclaration();
} else {
clash(originalData.getOriginalElement(), name);
return origDecl;
}
}
}
}
/**
* Convenience method to produce a data declaration in this module for the given original data declaration.
*
* @param originalDecl the original data declaration (must not be {@code null})
* @return the data declaration (not {@code null})
*/
public DataDeclaration declareData(DataDeclaration originalDecl) {
Assert.checkNotNullParam("originalDecl", originalDecl);
String name = originalDecl.getName();
Map definedObjects = this.moduleObjects;
synchronized (this) {
ProgramObject existing = definedObjects.get(name);
if (existing == null) {
// reuse original decl
definedObjects.put(name, originalDecl);
return originalDecl;
} else {
if (existing == originalDecl) {
// fast/common path
return originalDecl;
} else if (existing instanceof DataDeclaration decl) {
if (! originalDecl.getSymbolType().equals(decl.getSymbolType())) {
clash(originalDecl.getOriginalElement(), name);
return originalDecl;
}
return decl;
} else if (existing instanceof Data data) {
if (! originalDecl.getSymbolType().equals(data.getSymbolType())) {
clash(originalDecl.getOriginalElement(), name);
return originalDecl;
}
return data.getDeclaration();
} else {
clash(originalDecl.getOriginalElement(), name);
return originalDecl;
}
}
}
}
public DataDeclaration declareData(MemberElement originalElement, String name, ValueType type) {
Assert.checkNotNullParam("name", name);
Map definedObjects = this.moduleObjects;
synchronized (this) {
ProgramObject existing = definedObjects.get(name);
if (existing == null) {
DataDeclaration decl = new DataDeclaration(originalElement, this, name, type);
definedObjects.put(name, decl);
return decl;
} else {
if (existing instanceof DataDeclaration decl) {
if (! type.equals(decl.getValueType())) {
clash(originalElement, name);
}
return decl;
} else if (existing instanceof Data data) {
if (! type.equals(data.getValueType())) {
clash(originalElement, name);
}
return data.getDeclaration();
} else {
clash(originalElement, name);
return new DataDeclaration(originalElement, this, name, type);
}
}
}
}
void clash(final MemberElement originalElement, final String name) {
if (originalElement != null) {
originalElement.getEnclosingType().getContext().getCompilationContext().error(originalElement, "Object '%s' redeclared with different type", name);
} else {
getTypeDefinition().getContext().getCompilationContext().error("Synthetic object '%s' redeclared with different type", name);
}
}
private ModuleSection registerSection(final Section section) {
return new ModuleSection(section, typeSystem.getVoidType(), this);
}
public Iterable declarations() {
return new Iterable() {
@Override
public Iterator iterator() {
List decls;
synchronized (ProgramModule.this) {
decls = new ArrayList<>(moduleObjects.size());
for (ProgramObject programObject : moduleObjects.values()) {
if (programObject instanceof Declaration decl) {
decls.add(decl);
}
}
}
decls.sort(Comparator.comparing(ProgramObject::getName));
return decls.iterator();
}
};
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy