/*
* Copyright (c) 2016, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. 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.
*
* 3. Neither the name of the copyright holder 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 HOLDER 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.
*/
package com.oracle.truffle.llvm.parser.model.symbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.oracle.truffle.llvm.parser.model.symbols.constants.Constant;
import com.oracle.truffle.llvm.parser.model.symbols.constants.aggregate.AggregateConstant;
import com.oracle.truffle.llvm.parser.model.visitors.ConstantVisitor;
import com.oracle.truffle.llvm.runtime.types.MetaType;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.symbols.LLVMIdentifier;
import com.oracle.truffle.llvm.runtime.types.symbols.Symbol;
import com.oracle.truffle.llvm.runtime.types.symbols.ValueSymbol;
public final class Symbols {
private static final int INITIAL_CAPACITY = 16;
private Symbol[] symbols;
private int size;
public Symbols() {
symbols = new Symbol[INITIAL_CAPACITY];
}
private boolean hasSymbol(int index) {
return index >= 0 && index < symbols.length && symbols[index] != null && !(symbols[index] instanceof ForwardReference);
}
public Symbol getOrNull(int index) {
return hasSymbol(index) ? getSymbol(index) : null;
}
public void addSymbol(Symbol symbol) {
ensureCapacity(size + 1);
if (symbols[size] != null) {
final ForwardReference ref = (ForwardReference) symbols[size];
ref.replace(symbol);
if (ref.getName() != null && symbol instanceof ValueSymbol) {
((ValueSymbol) symbol).setName(ref.getName());
}
((ForwardReference) symbols[size]).replace(symbol);
}
symbols[size++] = symbol;
}
public void addSymbols(Symbols argSymbols) {
for (int i = 0; i < argSymbols.size; i++) {
addSymbol(argSymbols.symbols[i]);
}
}
public int getSize() {
return size;
}
public Symbol getSymbol(int index) {
if (index < size) {
return symbols[index];
}
throw new IllegalStateException("Dependent required for forward references");
}
public Symbol getSymbol(int index, Symbol dependent) {
if (index < size) {
return symbols[index];
} else {
ensureCapacity(index + 1);
ForwardReference ref = (ForwardReference) symbols[index];
if (ref == null) {
symbols[index] = ref = new ForwardReference();
}
ref.addDependent(dependent);
return ref;
}
}
public Symbol getSymbol(int index, AggregateConstant dependent, int elementIndex) {
if (index < size) {
return symbols[index];
} else {
ensureCapacity(index + 1);
ForwardReference ref = (ForwardReference) symbols[index];
if (ref == null) {
symbols[index] = ref = new ForwardReference();
}
ref.addDependent(dependent, elementIndex);
return ref;
}
}
public void setSymbolName(int index, String name) {
Symbol symbol = getSymbol(index);
if (symbol instanceof ValueSymbol) {
((ValueSymbol) symbol).setName(name);
}
if (index < size) {
if (symbols[index] instanceof ValueSymbol) {
((ValueSymbol) symbols[index]).setName(name);
}
} else {
ensureCapacity(index + 1);
ForwardReference ref = (ForwardReference) symbols[index];
if (ref == null) {
symbols[index] = ref = new ForwardReference();
}
ref.setName(name);
}
}
private void ensureCapacity(int capacity) {
while (symbols.length < capacity) {
symbols = Arrays.copyOf(symbols, symbols.length << 1);
}
}
@Override
public String toString() {
return "Symbols [symbols=" + Arrays.toString(Arrays.copyOfRange(symbols, 0, size)) + ", size=" + size + "]";
}
private static final class ForwardReference implements Constant, ValueSymbol {
private final List<Symbol> dependents = new ArrayList<>();
private final Map<AggregateConstant, List<Integer>> aggregateDependents = new HashMap<>();
private String name;
ForwardReference() {
this.name = null;
}
@Override
public void accept(ConstantVisitor visitor) {
}
void addDependent(Symbol dependent) {
dependents.add(dependent);
}
void addDependent(AggregateConstant dependent, int index) {
final List<Integer> indices = aggregateDependents.getOrDefault(dependent, new ArrayList<>());
indices.add(index);
aggregateDependents.put(dependent, indices);
}
public void replace(Symbol replacement) {
aggregateDependents.forEach((key, val) -> val.forEach(i -> key.replaceElement(i, replacement)));
dependents.forEach(dependent -> dependent.replace(this, replacement));
}
@Override
public Type getType() {
return MetaType.UNKNOWN;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("ForwardReference[name=%s]", name == null ? LLVMIdentifier.UNKNOWN : name);
}
}
}