/* * 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 java.util.Collections; import java.util.Iterator; import com.oracle.truffle.llvm.parser.model.generators.ModuleGenerator; import com.oracle.truffle.llvm.parser.records.Records; import com.oracle.truffle.llvm.parser.records.TypesRecord; import com.oracle.truffle.llvm.runtime.types.ArrayType; import com.oracle.truffle.llvm.runtime.types.DataSpecConverter; import com.oracle.truffle.llvm.runtime.types.FunctionType; import com.oracle.truffle.llvm.runtime.types.MetaType; import com.oracle.truffle.llvm.runtime.types.OpaqueType; import com.oracle.truffle.llvm.runtime.types.PointerType; import com.oracle.truffle.llvm.runtime.types.PrimitiveType; import com.oracle.truffle.llvm.runtime.types.StructureType; import com.oracle.truffle.llvm.runtime.types.Type; import com.oracle.truffle.llvm.runtime.types.VectorType; import com.oracle.truffle.llvm.runtime.types.VoidType; import com.oracle.truffle.llvm.runtime.types.visitors.TypeVisitor; public final class Types implements ParserListener, Iterable<Type> { private static Type[] toTypes(Types types, long[] args, long from, long to) { Type[] t = new Type[(int) (to - from)]; for (int i = 0; i < t.length; i++) { t[i] = types.get(args[(int) from + i]); } return t; } private final ModuleGenerator generator; private Type[] table = new Type[0]; private int size = 0; Types(ModuleGenerator generator) { this.generator = generator; } @Override public Iterator<Type> iterator() { return Collections.unmodifiableList(Arrays.asList(table)).iterator(); } @Override public void record(long id, long[] args) { TypesRecord record = TypesRecord.decode(id); Type type; switch (record) { case NUMBER_OF_ENTRIES: table = new Type[(int) args[0]]; return; case VOID: type = VoidType.INSTANCE; break; case FLOAT: type = PrimitiveType.FLOAT; break; case DOUBLE: type = PrimitiveType.DOUBLE; break; case LABEL: type = MetaType.LABEL; break; case OPAQUE: OpaqueType opaque = new OpaqueType(); if (table[size] != null) { if (table[size] instanceof UnresolvedNamedPointeeType) { opaque.setName(((UnresolvedNamedPointeeType) table[size]).getName()); } else { opaque.setName(((UnresolvedNamedType) table[size]).getName()); } } type = opaque; break; case INTEGER: type = Type.getIntegerType((int) args[0]); break; case POINTER: { int idx = (int) args[0]; if (idx > size) { table[size] = new PointerType(null); table[idx] = new UnresolvedPointeeType(size); size++; return; } else { type = new PointerType(get(idx)); } break; } case FUNCTION_OLD: { int i = 2; Type returnType = get(args[i++]); type = new FunctionType(returnType, toTypes(this, args, i, args.length), args[0] != 0); break; } case HALF: type = PrimitiveType.HALF; break; case ARRAY: type = new ArrayType(get(args[1]), (int) args[0]); break; case VECTOR: type = new VectorType((PrimitiveType) get(args[1]), (int) args[0]); break; case X86_FP80: type = PrimitiveType.X86_FP80; break; case FP128: type = PrimitiveType.F128; break; case PPC_FP128: type = PrimitiveType.PPC_FP128; break; case METADATA: type = MetaType.METADATA; break; case X86_MMX: type = MetaType.X86MMX; break; case STRUCT_ANON: type = new StructureType(args[0] != 0, toTypes(this, args, 1, args.length)); break; case STRUCT_NAME: { String name = Records.toString(args); if (table[size] instanceof UnresolvedPointeeType) { table[size] = new UnresolvedNamedPointeeType(name, ((UnresolvedPointeeType) table[size]).getIndex()); } else { table[size] = new UnresolvedNamedType(name); } return; } case STRUCT_NAMED: { StructureType structure = new StructureType(args[0] != 0, toTypes(this, args, 1, args.length)); if (table[size] != null) { if (table[size] instanceof UnresolvedNamedPointeeType) { structure.setName(((UnresolvedNamedPointeeType) table[size]).getName()); } else { structure.setName(((UnresolvedNamedType) table[size]).getName()); } } type = structure; break; } case FUNCTION: type = new FunctionType(get(args[1]), toTypes(this, args, 2, args.length), args[0] != 0); break; case TOKEN: type = MetaType.TOKEN; break; default: type = MetaType.UNKNOWN; break; } if (table[size] instanceof UnresolvedPointeeType) { PointerType pointer = (PointerType) table[((UnresolvedPointeeType) table[size]).getIndex()]; pointer.setPointeeType(type); generator.createType(pointer); } table[size++] = type; generator.createType(type); } public Type get(long index) { return table[(int) index]; } private static class UnresolvedPointeeType extends Type { private final int idx; UnresolvedPointeeType(int idx) { this.idx = idx; } @Override public void accept(TypeVisitor visitor) { // This is a private type only required for resolving throw new IllegalStateException(); } public int getIndex() { return idx; } @Override public int getBitSize() { // This is a private type only required for resolving throw new IllegalStateException(); } @Override public int getAlignment(DataSpecConverter targetDataLayout) { // This is a private type only required for resolving throw new IllegalStateException(); } @Override public int getSize(DataSpecConverter targetDataLayout) { // This is a private type only required for resolving throw new IllegalStateException(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + idx; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } UnresolvedPointeeType other = (UnresolvedPointeeType) obj; if (idx != other.idx) { return false; } return true; } } private static final class UnresolvedNamedPointeeType extends UnresolvedPointeeType { private final String name; UnresolvedNamedPointeeType(String name, int idx) { super(idx); this.name = name; } public String getName() { return name; } } private static final class UnresolvedNamedType extends Type { private final String name; UnresolvedNamedType(String name) { this.name = name; } @Override public void accept(TypeVisitor visitor) { // This is a private type only required for resolving } public String getName() { return name; } @Override public int getBitSize() { // This is a private type only required for resolving throw new IllegalStateException(); } @Override public int getAlignment(DataSpecConverter targetDataLayout) { // This is a private type only required for resolving throw new IllegalStateException(); } @Override public int getSize(DataSpecConverter targetDataLayout) { // This is a private type only required for resolving throw new IllegalStateException(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof UnresolvedNamedType)) { return false; } UnresolvedNamedType other = (UnresolvedNamedType) obj; if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } } @Override public String toString() { return "Types " + Arrays.toString(table); } }