/*
* 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.listeners;
import java.util.Arrays;
import com.oracle.truffle.llvm.parser.metadata.MDAttachment;
import com.oracle.truffle.llvm.parser.metadata.MDBaseNode;
import com.oracle.truffle.llvm.parser.metadata.MDBasicType;
import com.oracle.truffle.llvm.parser.metadata.MDCompileUnit;
import com.oracle.truffle.llvm.parser.metadata.MDCompositeType;
import com.oracle.truffle.llvm.parser.metadata.MDDerivedType;
import com.oracle.truffle.llvm.parser.metadata.MDEmptyNode;
import com.oracle.truffle.llvm.parser.metadata.MDEnumerator;
import com.oracle.truffle.llvm.parser.metadata.MDExpression;
import com.oracle.truffle.llvm.parser.metadata.MDFile;
import com.oracle.truffle.llvm.parser.metadata.MDFnNode;
import com.oracle.truffle.llvm.parser.metadata.MDGenericDebug;
import com.oracle.truffle.llvm.parser.metadata.MDGlobalVariable;
import com.oracle.truffle.llvm.parser.metadata.MDImportedEntity;
import com.oracle.truffle.llvm.parser.metadata.MDKind;
import com.oracle.truffle.llvm.parser.metadata.MDLexicalBlock;
import com.oracle.truffle.llvm.parser.metadata.MDLexicalBlockFile;
import com.oracle.truffle.llvm.parser.metadata.MDLocalVariable;
import com.oracle.truffle.llvm.parser.metadata.MDLocation;
import com.oracle.truffle.llvm.parser.metadata.MDMacro;
import com.oracle.truffle.llvm.parser.metadata.MDMacroFile;
import com.oracle.truffle.llvm.parser.metadata.MDModule;
import com.oracle.truffle.llvm.parser.metadata.MDNamedNode;
import com.oracle.truffle.llvm.parser.metadata.MDNamespace;
import com.oracle.truffle.llvm.parser.metadata.MDNode;
import com.oracle.truffle.llvm.parser.metadata.MDObjCProperty;
import com.oracle.truffle.llvm.parser.metadata.MDOldNode;
import com.oracle.truffle.llvm.parser.metadata.MDReference;
import com.oracle.truffle.llvm.parser.metadata.MDString;
import com.oracle.truffle.llvm.parser.metadata.MDSubprogram;
import com.oracle.truffle.llvm.parser.metadata.MDSubrange;
import com.oracle.truffle.llvm.parser.metadata.MDSubroutine;
import com.oracle.truffle.llvm.parser.metadata.MDSymbolReference;
import com.oracle.truffle.llvm.parser.metadata.MDTemplateType;
import com.oracle.truffle.llvm.parser.metadata.MDTemplateTypeParameter;
import com.oracle.truffle.llvm.parser.metadata.MDTemplateValue;
import com.oracle.truffle.llvm.parser.metadata.MDTypedValue;
import com.oracle.truffle.llvm.parser.metadata.MDValue;
import com.oracle.truffle.llvm.parser.metadata.MetadataList;
import com.oracle.truffle.llvm.parser.metadata.ParseUtil;
import com.oracle.truffle.llvm.parser.model.generators.SymbolGenerator;
import com.oracle.truffle.llvm.parser.records.DwTagRecord;
import com.oracle.truffle.llvm.parser.records.MetadataRecord;
import com.oracle.truffle.llvm.runtime.types.MetaType;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.VoidType;
public final class Metadata implements ParserListener {
public MDSymbolReference getSymbolReference(long typeId, long val) {
final Type argType = types.get(typeId);
if (argType == MetaType.METADATA || argType == VoidType.INSTANCE) {
return MDSymbolReference.VOID;
} else {
return new MDSymbolReference(argType, () -> generator.getSymbols().getOrNull((int) val));
}
}
private MDTypedValue getTypedValue(long typeId, long val) {
final Type argType = types.get(typeId);
if (argType == MetaType.METADATA) {
// this is a reference to an entry in the metadata list
return MDReference.fromIndex((int) val, metadata);
} else if (argType == VoidType.INSTANCE) {
return MDReference.VOID;
} else {
// this is a reference to an entry in the symbol table
return new MDSymbolReference(argType, () -> generator.getSymbols().getOrNull((int) val));
}
}
private final SymbolGenerator generator;
protected final Types types;
protected final MetadataList metadata;
Metadata(Types types, SymbolGenerator generator) {
this.types = types;
this.generator = generator;
metadata = generator.getMetadata();
}
// https://github.com/llvm-mirror/llvm/blob/release_38/include/llvm/Bitcode/LLVMBitCodes.h#L191
@Override
public void record(long id, long[] args) {
MetadataRecord record = MetadataRecord.decode(id);
switch (record) {
case STRING:
metadata.add(MDString.create(args));
break;
case VALUE:
metadata.add(MDValue.create38(args, this));
break;
case DISTINCT_NODE:
// we would only care if a node is distinct or not if we wanted to modify the ast
case NODE:
metadata.add(MDNode.create38(args, metadata));
break;
case NAME:
// read the name, this must be followed by a NAMED_NODE which will remove it again
metadata.add(MDString.create(args));
break;
case KIND:
metadata.addKind(MDKind.create(args));
break;
case LOCATION:
metadata.add(MDLocation.create38(args, metadata));
break;
case OLD_NODE:
createOldNode(args);
break;
case OLD_FN_NODE:
createOldFnNode(args);
break;
case NAMED_NODE:
createNamedNode(args);
break;
case ATTACHMENT:
createAttachment(args);
break;
case GENERIC_DEBUG:
metadata.add(MDGenericDebug.create38(args, metadata));
break;
case SUBRANGE:
metadata.add(MDSubrange.create38(args));
break;
case ENUMERATOR:
metadata.add(MDEnumerator.create38(args, metadata));
break;
case BASIC_TYPE:
metadata.add(MDBasicType.create38(args, metadata));
break;
case FILE:
metadata.add(MDFile.create38(args, metadata));
break;
case SUBPROGRAM:
metadata.add(MDSubprogram.create38(args, metadata, this::getSymbolReference));
break;
case SUBROUTINE_TYPE:
metadata.add(MDSubroutine.create38(args, metadata));
break;
case LEXICAL_BLOCK:
metadata.add(MDLexicalBlock.create38(args, metadata));
break;
case LEXICAL_BLOCK_FILE:
metadata.add(MDLexicalBlockFile.create38(args, metadata));
break;
case LOCAL_VAR:
metadata.add(MDLocalVariable.create38(args, metadata));
break;
case NAMESPACE:
metadata.add(MDNamespace.create38(args, metadata));
break;
case GLOBAL_VAR:
metadata.add(MDGlobalVariable.create38(args, metadata));
break;
case DERIVED_TYPE:
metadata.add(MDDerivedType.create38(args, metadata));
break;
case COMPOSITE_TYPE:
metadata.add(MDCompositeType.create38(args, metadata));
break;
case COMPILE_UNIT:
metadata.add(MDCompileUnit.create38(args, metadata));
break;
case TEMPLATE_TYPE:
metadata.add(MDTemplateType.create38(args, metadata));
break;
case TEMPLATE_VALUE:
metadata.add(MDTemplateValue.create38(args, metadata));
break;
case EXPRESSION:
createExpression(args);
break;
case OBJC_PROPERTY:
metadata.add(MDObjCProperty.create38(args, metadata));
break;
case IMPORTED_ENTITY:
metadata.add(MDImportedEntity.create38(args, metadata));
break;
case MODULE:
metadata.add(MDModule.create38(args, metadata));
break;
case MACRO:
metadata.add(MDMacro.create38(args, metadata));
break;
case MACRO_FILE:
metadata.add(MDMacroFile.create38(args, metadata));
break;
case STRINGS: {
// since llvm 3.9 all metadata strings are emitted as a single blob
final MDString[] strings = MDString.createFromBlob(args);
for (final MDString string : strings) {
metadata.add(string);
}
break;
}
default:
metadata.add(null);
throw new UnsupportedOperationException("Unsupported Metadata Record: " + record);
}
}
private void createNamedNode(long[] args) {
final MDString nameStringNode = (MDString) metadata.removeLast();
final MDNamedNode node = new MDNamedNode(nameStringNode.getString());
for (long arg : args) {
node.add(metadata.getMDRefOrNullRef(arg));
}
metadata.addNamed(node);
}
private void createAttachment(long[] args) {
if (args.length <= 0) {
throw new IllegalStateException();
}
final int offset = args.length % 2;
for (int i = offset; i < args.length; i += 2) {
final MDKind kind = metadata.getKind(args[i]);
final MDReference md = metadata.getMDRef(args[i + 1]);
final MDAttachment attachment = new MDAttachment(kind, md);
if (offset != 0) {
metadata.addAttachment(args[0], attachment);
} else {
metadata.addAttachment(attachment);
}
}
}
private MDSymbolReference getSymbolReference(long index) {
if (index > 0) {
return new MDSymbolReference(types.get(index), () -> generator.getSymbols().getOrNull((int) index));
} else {
return MDSymbolReference.VOID;
}
}
private static final int EXPRESSION_ARGSTARTINDEX = 1;
private void createExpression(long[] args) {
// TODO handle
final long[] elements = Arrays.copyOfRange(args, EXPRESSION_ARGSTARTINDEX, args.length);
metadata.add(new MDExpression(elements));
}
private MDTypedValue[] getTypedValues(long[] args) {
assert args.length % 2 == 0; // should be type/value pairs
final MDTypedValue[] elements = new MDTypedValue[args.length / 2];
for (int i = 0; i < elements.length; i++) {
final int index = i * 2;
elements[i] = getTypedValue(args[index], args[index + 1]);
}
return elements;
}
private static final int ARGINDEX_IDENT = 0;
private void createOldNode(long[] args) {
final MDTypedValue[] elements = getTypedValues(args);
if (ParseUtil.isInt(elements[ARGINDEX_IDENT]) && DwTagRecord.isDwarfDescriptor(ParseUtil.asInt64(elements[ARGINDEX_IDENT]))) {
// this is a debug information descriptor as described in
// http://releases.llvm.org/3.2/docs/SourceLevelDebugging.html#debug_info_descriptors
final int ident = ParseUtil.asInt32(elements[ARGINDEX_IDENT]);
final DwTagRecord record = DwTagRecord.decode(ident);
if (elements.length == 1 && record != DwTagRecord.DW_TAG_UNKNOWN) {
metadata.add(MDEmptyNode.create(record));
return;
}
switch (record) {
case DW_TAG_COMPILE_UNIT:
metadata.add(MDCompileUnit.create32(elements));
break;
case DW_TAG_FILE_TYPE:
metadata.add(MDFile.create32(elements));
break;
case DW_TAG_CONSTANT:
case DW_TAG_VARIABLE:
// descriptor for a global variable or constant
metadata.add(MDGlobalVariable.create32(elements));
break;
case DW_TAG_SUBPROGRAM:
metadata.add(MDSubprogram.create32(elements));
break;
case DW_TAG_LEXICAL_BLOCK:
metadata.add(createLexicalBlock(elements));
break;
case DW_TAG_BASE_TYPE:
metadata.add(MDBasicType.create32(elements));
break;
case DW_TAG_FORMAL_PARAMETER:
case DW_TAG_MEMBER:
case DW_TAG_POINTER_TYPE:
case DW_TAG_REFERENCE_TYPE:
case DW_TAG_TYPEDEF:
case DW_TAG_CONST_TYPE:
case DW_TAG_VOLATILE_TYPE:
case DW_TAG_RESTRICT_TYPE:
case DW_TAG_FRIEND:
metadata.add(MDDerivedType.create32(elements));
break;
case DW_TAG_CLASS_TYPE:
case DW_TAG_ARRAY_TYPE:
case DW_TAG_ENUMERATION_TYPE:
case DW_TAG_STRUCTURE_TYPE:
case DW_TAG_UNION_TYPE:
case DW_TAG_VECTOR_TYPE:
case DW_TAG_INHERITANCE:
case DW_TAG_SUBROUTINE_TYPE:
metadata.add(MDCompositeType.create32(elements));
break;
case DW_TAG_SUBRANGE_TYPE:
metadata.add(MDSubrange.create32(elements));
break;
case DW_TAG_ENUMERATOR:
metadata.add(MDEnumerator.create32(elements));
break;
case DW_TAG_AUTO_VARIABLE:
case DW_TAG_ARG_VARIABLE:
case DW_TAG_RETURN_VARIABLE:
metadata.add(MDLocalVariable.create32(elements));
break;
case DW_TAG_UNKNOWN:
metadata.add(MDOldNode.create32(elements));
break;
case DW_TAG_TEMPLATE_TYPE_PARAMETER:
metadata.add(MDTemplateTypeParameter.create32(elements));
break;
case DW_TAG_TEMPLATE_VALUE_PARAMETER:
metadata.add(MDTemplateValue.create32(elements));
break;
case DW_TAG_NAMESPACE:
metadata.add(MDNamespace.create32(elements));
break;
default:
metadata.add(null);
throw new UnsupportedOperationException("Unsupported Dwarf Record: " + record);
}
} else {
metadata.add(MDOldNode.create32(elements));
}
}
private static final int LEXICALBLOCK_DISTINCTOR_ARGINDEX = 2;
private static MDBaseNode createLexicalBlock(MDTypedValue[] values) {
final MDTypedValue distinctor = values[LEXICALBLOCK_DISTINCTOR_ARGINDEX];
if (ParseUtil.isInt(distinctor)) {
// lexical block
return MDLexicalBlock.create32(values);
} else {
// lexical block file
return MDLexicalBlockFile.create32(values);
}
}
private static final int OLDFNNODE_ARGINDEX_TYPE = 0;
private static final int OLDFNNODE_ARGINDEX_VALUE = 1;
private static final int OLDFNNODE_ARGCOUNT = 2;
private void createOldFnNode(long[] args) {
final MDTypedValue val = getTypedValue(args[OLDFNNODE_ARGINDEX_TYPE], args[OLDFNNODE_ARGINDEX_VALUE]);
if (args.length != OLDFNNODE_ARGCOUNT) {
throw new UnsupportedOperationException("OldFnNode with multiple values is not supported!");
}
metadata.add(MDFnNode.create(val));
}
}