/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2006-2010.
*/
package x10cpp.debug;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.Map;
import polyglot.types.Context;
import polyglot.types.MemberDef;
import polyglot.types.MethodDef;
import polyglot.types.ProcedureDef;
import polyglot.types.Ref;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.util.QuotedStringTokenizer;
import polyglot.util.StringUtil;
import polyglot.util.CollectionUtil; import x10.util.CollectionFactory;
import x10.util.ClassifiedStream;
import x10cpp.visit.Emitter;
/**
* Map from generated filename and line to source filename and line.
* (C++ filename (String), C++ line number range (int, int)) ->
* (X10 filename (String), X10 line number (int)).
* Also stores the method mapping.
*
* @author igor
*/
public class LineNumberMap extends StringTable {
/** A map key representing a C++ source file/line range combination. */
private static class Key {
public final int fileId;
public final int start_line;
public final int end_line;
public Key(int f, int s, int e) {
fileId = f;
start_line = s;
end_line = e;
}
public String toString() {
return fileId + ":" + start_line + "-" + end_line;
}
public int hashCode() {
return fileId + start_line + end_line;
}
public boolean equals(Object o) {
if (getClass() != o.getClass()) return false;
Key k = (Key) o;
return fileId == k.fileId && start_line == k.start_line && end_line == k.end_line;
}
}
/** A map entry representing an X10 source file/line combination. */
private static class Entry {
public final int fileId;
public final int line;
public final int column;
public Entry(int f, int l, int c) {
fileId = f;
line = l;
column = c;
}
public String toString() {
return fileId + ":" + line;
}
}
private final Map<Key, Entry> map;
private static class MethodDescriptor {
public final int returnType;
public final int container;
public final int name;
public final int[] args;
public final Key lines;
public MethodDescriptor(int returnType, int container, int name, int[] args, Key lines) {
this.returnType = returnType;
this.container = container;
this.name = name;
this.args = args;
this.lines = lines;
}
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass())
return false;
MethodDescriptor md = (MethodDescriptor) obj;
if (md.name != name || md.container != container ||
md.returnType != returnType || md.args.length != args.length)
{
return false;
}
for (int i = 0; i < args.length; i++) {
if (args[i] != md.args[i])
return false;
}
return true;
}
public int hashCode() {
int h = name;
h = 31*h + container;
h = 31*h + returnType;
for (int arg : args) {
h = 31*h + arg;
}
return h;
}
public String toString() {
StringBuilder res = new StringBuilder();
res.append(returnType).append(" ");
res.append(container).append(".");
res.append(name).append("(");
boolean first = true;
for (int arg : args) {
if (!first) res.append(",");
first = false;
res.append(arg);
}
res.append(")");
res.append("{").append(lines.fileId);
res.append(",").append(lines.start_line);
res.append(",").append(lines.end_line);
res.append("}");
return res.toString();
}
public static MethodDescriptor parse(String str) {
StringTokenizer st = new StringTokenizer(str, ". (),", true);
String s = st.nextToken(" ");
int r = Integer.parseInt(s);
s = st.nextToken();
assert (s.equals(" "));
s = st.nextToken(".");
int c = Integer.parseInt(s);
s = st.nextToken();
assert (s.equals("."));
s = st.nextToken("(");
int n = Integer.parseInt(s);
s = st.nextToken();
assert (s.equals("("));
ArrayList<String> al = new ArrayList<String>();
while (st.hasMoreTokens()) {
String t = st.nextToken(",)");
if (t.equals(")"))
break;
al.add(t);
t = st.nextToken();
if (t.equals(")"))
break;
assert (t.equals(","));
}
int[] a = new int[al.size()];
for (int i = 0; i < a.length; i++) {
a[i] = Integer.parseInt(al.get(i));
}
s = st.nextToken("{,}");
assert (s.equals("{"));
s = st.nextToken();
int f = Integer.parseInt(s);
s = st.nextToken();
int l = Integer.parseInt(s);
s = st.nextToken();
int e = Integer.parseInt(s);
s = st.nextToken();
assert (s.equals("}"));
Key k = new Key(f, l, e);
assert (!st.hasMoreTokens());
return new MethodDescriptor(r, c, n, a, k);
}
public String toPrettyString(LineNumberMap map) {
return toPrettyString(map, true);
}
public String toPrettyString(LineNumberMap map, boolean includeReturnType) {
StringBuilder res = new StringBuilder();
if (includeReturnType)
res.append(map.lookupString(returnType)).append(" ");
res.append(map.lookupString(container)).append("::");
res.append(map.lookupString(name)).append("(");
boolean first = true;
for (int arg : args) {
if (!first) res.append(",");
first = false;
res.append(map.lookupString(arg));
}
res.append(")");
return res.toString();
}
}
private final Map<MethodDescriptor, MethodDescriptor> methods;
/**
*/
public LineNumberMap() {
this(new ArrayList<String>());
}
private LineNumberMap(ArrayList<String> strings) {
super(strings);
this.map = CollectionFactory.newHashMap();
this.methods = CollectionFactory.newHashMap();
}
/**
* @param cppFile C++ filename
* @param startLine C++ start line number
* @param endLine C++ end line number
* @param sourceFile X10 filename
* @param sourceLine X10 line number
*/
public void put(String cppFile, int startLine, int endLine, String sourceFile, int sourceLine, int sourceColumn) {
map.put(new Key(stringId(cppFile), startLine, endLine), new Entry(stringId(sourceFile), sourceLine, sourceColumn));
}
private MethodDescriptor createMethodDescriptor(String container, String name, String returnType, String[] args, Key l) {
int c = stringId(container);
int n = stringId(name);
int r = stringId(returnType);
int[] a = new int[args.length];
for (int i = 0; i < a.length; i++) {
a[i] = stringId(args[i]);
}
return new MethodDescriptor(r, c, n, a, l);
}
/**
* @param def X10 method or constructor signature
* @param cppFile generated file containing the method body
* @param startLine first generated line of the method body
* @param endLine last generated line of the method body
*/
public void addMethodMapping(MemberDef def, String cppFile, int startLine, int endLine, int lastX10Line) {
Key tk = new Key(stringId(cppFile), startLine, endLine);
Type container = def.container().get();
assert (def instanceof ProcedureDef);
String name = (def instanceof MethodDef) ? ((MethodDef) def).name().toString() : null;
Type returnType = (def instanceof MethodDef) ? ((MethodDef) def).returnType().get() : null;
List<Ref<? extends Type>> formalTypes = ((ProcedureDef) def).formalTypes();
addMethodMapping(container, name, returnType, formalTypes, tk, lastX10Line);
}
private void addMethodMapping(Type c, String n, Type r, List<Ref<? extends Type>> f, Key tk, int lastX10Line) {
assert (c != null);
assert (f != null);
String sc = c.toString().replace("$", "::");
String sn = n == null ? TypeSystem.CONSTRUCTOR_NAME : n;
String sr = r == null ? "" : r.toString();
String[] sa = new String[f.size()];
for (int i = 0; i < sa.length; i++) {
sa[i] = f.get(i).get().toString();
}
MethodDescriptor src = createMethodDescriptor(sc, sn, sr, sa, new Key(-1, -1, lastX10Line));
String tc = Emitter.translateType(c);
String tn = n == null ? "_constructor" : Emitter.mangled_method_name(n);
String tr = r == null ? "void" : Emitter.translateType(r, true);
String[] ta = new String[sa.length];
for (int i = 0; i < ta.length; i++) {
ta[i] = Emitter.translateType(f.get(i).get(), true);
}
MethodDescriptor tgt = createMethodDescriptor(tc, tn, tr, ta, tk);
// TODO: This line below causes the X10 standard library to fail to compile with the -DEBUG flag. Why?
// assert (methods.get(tgt) == null);
methods.put(tgt, src);
}
private class LocalVariableMapInfo
{
int _x10name; // Index of the X10 variable name in _X10strings
int _x10type; // Classification of this type
int _x10typeIndex; // Index of the X10 type into appropriate _X10ClassMap, _X10ClosureMap (if applicable)
int _cppName; // Index of the C++ variable name in _X10strings
String _x10index; // Index of X10 file name in _X10sourceList
int _x10startLine; // First line number of X10 line range
int _x10endLine; // Last line number of X10 line range
}
private class MemberVariableMapInfo
{
int _x10type; // Classification of this type
int _x10typeIndex; // Index of the X10 type into appropriate _X10typeMap
int _x10memberName; // Index of the X10 member name in _X10strings
int _cppMemberName; // Index of the C++ member name in _X10strings
int _cppClass; // Index of the C++ containing struct/class name in _X10strings
}
private class ClassMapInfo
{
int _x10startLine; // First line number of X10 line range
int _x10endLine; // Last line number of X10 line range
int _type; // used to store the wrapping type id
String _sizeOfArg;
String _file;
ArrayList<MemberVariableMapInfo> _members;
}
private class LoopVariable
{
String realName;
int startLine;
int endLine;
}
private LinkedHashMap<String, ArrayList<LoopVariable>> loopVariables;
private ArrayList<Integer> arrayMap = new ArrayList<Integer>();
//private ArrayList<Integer> refMap = new ArrayList<Integer>();
private ArrayList<LocalVariableMapInfo> localVariables;
private LinkedHashMap<Integer, ClassMapInfo> memberVariables;
private LinkedHashMap<Integer, ClassMapInfo> referenceMembers;
private LinkedHashMap<Integer, ClassMapInfo> closureMembers;
// the type numbers were provided by Steve Cooper in "x10dbg_types.h"
static int determineTypeId(String type)
{
if (type == null)
return 0;
if (type.equals("x10.lang.Int") || type.startsWith("x10.lang.Int{"))
return 6;
if (type.startsWith("x10.array.Array"))
return 200;
if (type.startsWith("x10.lang.PlaceLocalHandle"))
return 203;
if (type.equals("x10.lang.Boolean") || type.startsWith("x10.lang.Boolean{"))
return 1;
if (type.equals("x10.lang.Byte") || type.startsWith("x10.lang.Byte{"))
return 2;
if (type.equals("x10.lang.Char") || type.startsWith("x10.lang.Char{"))
return 3;
if (type.equals("x10.lang.Double") || type.startsWith("x10.lang.Double{"))
return 4;
if (type.equals("x10.lang.Float") || type.startsWith("x10.lang.Float{"))
return 5;
if (type.equals("x10.lang.Long") || type.startsWith("x10.lang.Long{"))
return 7;
if (type.equals("x10.lang.Short") || type.startsWith("x10.lang.Short{"))
return 8;
if (type.equals("x10.lang.UByte") || type.startsWith("x10.lang.UByte{"))
return 9;
if (type.equals("x10.lang.UInt") || type.startsWith("x10.lang.UInt{"))
return 10;
if (type.equals("x10.lang.ULong") || type.startsWith("x10.lang.ULong{"))
return 11;
if (type.equals("x10.lang.UShort") || type.startsWith("x10.lang.UShort{"))
return 12;
if (type.startsWith("x10.array.DistArray"))
return 202;
if (type.startsWith("x10.array.Dist"))
return 201;
if (type.startsWith("x10.lang.Place"))
return 204;
if (type.startsWith("x10.util.Random"))
return 205;
if (type.startsWith("x10.lang.String"))
return 206;
// 207 = valrail
if (type.startsWith("x10.array.Point"))
return 208;
if (type.startsWith("x10.lang.Any"))
return 209;
if (type.startsWith("x10.lang.GlobalRef"))
return 210;
if (type.startsWith("x10.lang.IntRange"))
return 212;
if (type.startsWith("x10.lang.LongRange"))
return 213;
if (type.startsWith("x10.array.Region"))
return 300;
if (type.contains("_closure_"))
return 100;
return 101; // generic class
// type 102 = generic structure
// type 103 = generic base class
}
static String getInnerType(String type)
{
int bracketStart = type.indexOf('[');
int bracketEnd = type.lastIndexOf(']');
if (bracketStart != -1 && bracketEnd != -1)
return type.substring(bracketStart+1, bracketEnd);
else
return null;
}
int determineSubtypeId(String type, ArrayList<Integer> list)
{
String subtype = getInnerType(type);
if (subtype != null)
{
int subtypeId = determineTypeId(subtype);
int position = list.size();
list.add(subtypeId);
int innerType = determineSubtypeId(subtype, list);
if (subtypeId == 101 && innerType == -1) // this may be a locally defined class. Remember the whole name.
innerType = stringId(Emitter.mangled_non_method_name(subtype));
list.add(innerType);
return position/2;
}
else
return -1;
}
public int addReferenceMap(String name, String type, int startline, int endline, int refType)
{
if (type.contains("$Anonymous$") || type.equals("x10.lang.PlaceLocalHandle[T]")) // can't properly account for these types
return -1;
if (referenceMembers == null)
referenceMembers = new LinkedHashMap<Integer, ClassMapInfo>();
int id = stringId(name);
ClassMapInfo cm = referenceMembers.get(id);
if (cm == null)
{
cm = new ClassMapInfo();
cm._members = new ArrayList<LineNumberMap.MemberVariableMapInfo>();
if (refType == 211)
cm._type = 203; // special case
else
cm._type = refType;
cm._sizeOfArg = type.replace(".", "::").replace('[', '<').replace("]", " >").replace("$", "__");
int properties = cm._sizeOfArg.indexOf('{');
if (properties > -1)
{
String end;
while (properties > -1)
{
end = cm._sizeOfArg.substring(cm._sizeOfArg.indexOf('}')+1);
cm._sizeOfArg = cm._sizeOfArg.substring(0, properties);
cm._sizeOfArg = cm._sizeOfArg.concat(end);
properties = cm._sizeOfArg.indexOf('{');
}
}
int comma = cm._sizeOfArg.indexOf(',');
if (comma > -1) // multiple arguments
{
// this has template arguments. Add in the TPMGL stuff
int start = cm._sizeOfArg.indexOf('<');
while (start < comma)
{
int nextStart = cm._sizeOfArg.indexOf('<', start+1);
if (nextStart < comma && nextStart != -1)
start = nextStart;
else
break;
}
String temp = cm._sizeOfArg.substring(start+1).replace(",", "), class TPMGL(").replaceFirst(">", ")>");
cm._sizeOfArg = cm._sizeOfArg.substring(0, start+1).concat("class TPMGL(").concat(temp);
}
else // single argument
{
int argstart = cm._sizeOfArg.lastIndexOf('<');
if (argstart > 0)
{
int argend = cm._sizeOfArg.indexOf('>');
if (cm._sizeOfArg.substring(argstart, argend).indexOf(':') == -1)
{
String temp = cm._sizeOfArg.substring(0, argstart+1) + "class TPMGL(";
temp = temp + cm._sizeOfArg.substring(argstart+1, argend) + ")";
cm._sizeOfArg = temp + cm._sizeOfArg.substring(argend);
}
}
}
referenceMembers.put(id, cm);
int returnValue = referenceMembers.size()-1;
String innerType = getInnerType(type);
MemberVariableMapInfo v = new MemberVariableMapInfo();
if (refType == 211)
{
v._x10type = 211;
innerType = getInnerType(type);
}
else
v._x10type = determineTypeId(innerType);
if (v._x10type == 200 || v._x10type == 202 || v._x10type == 204 || v._x10type == 207 || v._x10type == 211)
v._x10typeIndex = determineSubtypeId(innerType, arrayMap);
else
v._x10typeIndex = -1;
if (refType == 210) // Debug team wants the target's name, not the variable name, for GlobalRefs
{
int nameStart=type.indexOf("self==");
if (nameStart == -1)
v._x10memberName = id;
else
{
nameStart+=6;
int nameEnd = type.indexOf(',', nameStart);
if (nameEnd == -1)
nameEnd = type.indexOf('}', nameStart);
if (nameEnd == -1)
v._x10memberName = id;
else
v._x10memberName = stringId(type.substring(nameStart, nameEnd));
}
v._cppMemberName = v._x10memberName;
}
else if (refType == 202) // create additional maps for internal components of DistArray.
{
v._x10typeIndex = addReferenceMap(name+"_localHandle", "x10.lang.PlaceLocalHandle[x10.array.DistArray__LocalState["+innerType+"]]", startline, endline, 211);
// I hate that this is here. It's just a hardcoded representation of the internals of DistArray.
// It does not belong here, but the debugger people can't seem to work without it.
// we add something called "dist" here, and the main "v" entry is "localHandle"
MemberVariableMapInfo dist = new MemberVariableMapInfo();
dist._x10type = 201;
dist._x10typeIndex = -1;
dist._x10memberName = stringId("dist");
dist._cppMemberName = stringId("x10__dist");
dist._cppClass = stringId("x10::array::Dist");
cm._members.add(dist);
v._x10type = 203;
v._x10memberName = stringId("localHandle");
v._cppMemberName = stringId("x10__localHandle");
}
else if (refType == 211)
{
v._x10memberName = id;
v._cppMemberName = stringId("x10__localStorage");
}
else
{
v._x10memberName = id;
v._cppMemberName = v._x10memberName;
}
v._cppClass = stringId(cm._sizeOfArg);
cm._members.add(v);
return returnValue;
}
int index = 0;
for (int key : referenceMembers.keySet())
{
if (id == key)
return index;
else
index++;
}
// should never reach here
return -1;
}
public void rememberLoopVariable(String declaredName, String realName, int startLine, int endLine)
{
if (loopVariables == null)
loopVariables = new LinkedHashMap<String, ArrayList<LoopVariable>>();
ArrayList<LoopVariable> list = loopVariables.get(declaredName);
if (list == null)
{
list = new ArrayList<LineNumberMap.LoopVariable>();
loopVariables.put(declaredName, list);
}
LoopVariable lv = new LoopVariable();
lv.realName = realName;
lv.startLine = startLine;
lv.endLine = endLine;
list.add(lv);
}
public void addLocalVariableMapping(String name, String type, int startline, int endline, String file, boolean noMangle, int closureIndex, boolean isStruct)
{
//if (name == null || name.startsWith(Context.MAGIC_VAR_PREFIX))
if (name == null || name.contains("$"))
return; // skip variables with compiler-generated names.
if (localVariables == null)
localVariables = new ArrayList<LineNumberMap.LocalVariableMapInfo>();
LocalVariableMapInfo v = new LocalVariableMapInfo();
v._x10name = stringId(name);
v._x10type = determineTypeId(type);
if (v._x10type == 203 || v._x10type == 210 || v._x10type == 202)
v._x10typeIndex = addReferenceMap(name, type, startline, endline, v._x10type);
else if (v._x10type == 200 || v._x10type == 204 || v._x10type == 207)
v._x10typeIndex = determineSubtypeId(type, arrayMap);
else if (v._x10type == 101)
{
int b = type.indexOf('{');
if (b == -1)
v._x10typeIndex = stringId(Emitter.mangled_non_method_name(type));
else
v._x10typeIndex = stringId(Emitter.mangled_non_method_name(type.substring(0, b)));
if (isStruct)
v._x10type = 102;
}
else if (v._x10type == 100 || closureIndex == -2)
v._x10typeIndex = closureIndex;
else
v._x10typeIndex = -1;
if (noMangle)
v._cppName = v._x10name;
else
v._cppName = stringId(Emitter.mangled_non_method_name(name));
v._x10index = file;
v._x10startLine = startline;
v._x10endLine = endline;
// prevent duplicates
for (LocalVariableMapInfo existing : localVariables)
{
if (existing._x10name == v._x10name && existing._cppName == v._cppName && existing._x10index.equals(v._x10index)
&& existing._x10startLine == v._x10startLine && existing._x10endLine == v._x10endLine)
{
if ((existing._x10type == v._x10type && existing._x10typeIndex == v._x10typeIndex) || v._x10type == 209)
return; // exact duplicate, or less specific type
else if (existing._x10type == 209)
{ // replace "Any" with the more specific type
existing._x10type = v._x10type;
existing._x10typeIndex = v._x10typeIndex;
return;
}
}
}
// convert loop indexes
if (v._x10type < 100 && loopVariables != null && loopVariables.containsKey(name))
{
ArrayList<LoopVariable> list = loopVariables.get(name);
for (LoopVariable lv : list)
{
if (lv.startLine == v._x10startLine && lv.endLine == v._x10endLine)
{
v._cppName = stringId(lv.realName);
break;
}
}
}
localVariables.add(v);
}
public void addClassMemberVariable(String name, String type, String containingClass, boolean isStruct, boolean isConstructorArg, boolean isSuper)
{
if (containingClass.indexOf('{') != -1 || containingClass.indexOf("[") != -1) // skip these - the compiler didn't flag them properly
return;
if (memberVariables == null)
memberVariables = new LinkedHashMap<Integer, ClassMapInfo>();
ClassMapInfo cm = memberVariables.get(stringId(containingClass));
if (cm == null)
{
cm = new ClassMapInfo();
cm._members = new ArrayList<LineNumberMap.MemberVariableMapInfo>();
if (isStruct)
cm._type = 102;
else
cm._type = 101;
memberVariables.put(stringId(containingClass), cm);
}
if (name == null) return; // special case for classes without members
MemberVariableMapInfo v = new MemberVariableMapInfo();
v._x10type = determineTypeId(type);
if (v._x10type == 101)
{
int b = type.indexOf('{');
if (b == -1)
v._x10typeIndex = stringId(Emitter.mangled_non_method_name(type));
else
v._x10typeIndex = stringId(Emitter.mangled_non_method_name(type.substring(0, b)));
if (isStruct)
v._x10type = 102;
}
else if (v._x10type == 203 || v._x10type == 210 || v._x10type == 202)
v._x10typeIndex = addReferenceMap(name, type, 0, 0, v._x10type);
else if (v._x10type == 200 || v._x10type == 204 || v._x10type == 207)
v._x10typeIndex = determineSubtypeId(type, arrayMap);
else
v._x10typeIndex = -1;
if (isConstructorArg)
v._x10memberName = stringId("{...}");
else
v._x10memberName = stringId(name);
if (isSuper)
{
v._x10type = 103;
v._cppMemberName = stringId(Emitter.mangled_non_method_name(name));
}
else
v._cppMemberName = stringId("x10__"+Emitter.mangled_non_method_name(name));
v._cppClass = stringId(Emitter.translateFQN(containingClass));
cm._members.add(v);
}
public void addClosureMember(String name, String type, String containingClass, String containerWithTemplateArgs, String file, int startLine, int endLine)
{
if (closureMembers == null)
closureMembers = new LinkedHashMap<Integer, ClassMapInfo>();
ClassMapInfo cm = closureMembers.get(stringId(containingClass));
if (cm == null)
{
addLocalVariableMapping("this", containingClass, startLine, endLine, file, true, closureMembers.size(), false);
cm = new ClassMapInfo();
cm._members = new ArrayList<LineNumberMap.MemberVariableMapInfo>();
cm._sizeOfArg = containerWithTemplateArgs.replace("TPMGL(", " class TPMGL(");
cm._type = 100; // all closures are type 100
cm._file = file;
closureMembers.put(stringId(containingClass), cm);
}
MemberVariableMapInfo v = new MemberVariableMapInfo();
v._x10type = determineTypeId(type);
if (v._x10type == 203 || v._x10type == 210 || v._x10type == 202)
v._x10typeIndex = addReferenceMap(name, type, startLine, endLine, v._x10type);
else if (v._x10type == 200 || v._x10type == 204 || v._x10type == 207)
v._x10typeIndex = determineSubtypeId(type, arrayMap);
else if (v._x10type == 101) // save the type for later - it may be a class in our class table
v._x10typeIndex = stringId(Emitter.mangled_non_method_name(type));
else
v._x10typeIndex = -1;
v._x10memberName = stringId(name);
v._cppMemberName = stringId(Emitter.mangled_non_method_name(name));
v._cppClass = stringId(containingClass);
// prevent duplicates
for (MemberVariableMapInfo existing : cm._members)
{
if (existing._x10memberName == v._x10memberName && existing._cppMemberName == v._cppMemberName && existing._cppClass == v._cppClass)
{
if ((existing._x10type == v._x10type && existing._x10typeIndex == v._x10typeIndex) || v._x10type == 209)
return; // exact duplicate, or less specific type
else if (existing._x10type == 209)
{ // replace "Any" with the more specific type
existing._x10type = v._x10type;
existing._x10typeIndex = v._x10typeIndex;
cm._x10startLine = startLine;
cm._x10endLine = endLine;
return;
}
}
}
cm._x10startLine = startLine;
cm._x10endLine = endLine;
cm._members.add(v);
}
/**
* @param method target method signature
* @return source method signature
*/
public String getMappedMethod(String method) {
for (MethodDescriptor m : methods.keySet()) {
String mm = m.toPrettyString(this, false);
if (mm.equals(method))
return methods.get(m).toPrettyString(this, false);
}
return null;
}
public String toString() {
final StringBuilder sb = new StringBuilder();
for (Key pos : map.keySet()) {
Entry entry = map.get(pos);
sb.append(lookupString(pos.fileId)).append(":").append(pos.start_line).append("->");
sb.append(lookupString(entry.fileId)).append(":").append(entry.line).append("\n");
}
sb.append("\n");
for (MethodDescriptor md : methods.keySet()) {
MethodDescriptor sm = methods.get(md);
sb.append(md.toPrettyString(this, true)).append("->");
sb.append(sm.toPrettyString(this, true)).append("\n");
}
return sb.toString();
}
/**
* Is the map empty?
* @return true if the map is empty.
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* Produces a string suitable for initializing a field in the generated file.
* The resulting string can be parsed by {@link #importMap(String)}.
*/
public String exportMap() {
final StringBuilder sb = new StringBuilder();
sb.append("F");
exportStringMap(sb);
sb.append(" L{");
for (Key pos : map.keySet()) {
Entry entry = map.get(pos);
sb.append(pos.fileId).append(":");
sb.append(pos.start_line).append("-").append(pos.end_line).append("->");
sb.append(entry.fileId).append(":").append(entry.line).append(",");
}
sb.append("} M{");
for (MethodDescriptor md : methods.keySet()) {
MethodDescriptor sm = methods.get(md);
sb.append(md.toString()).append("->").append(sm.toString()).append(";");
}
sb.append("}");
return sb.toString();
}
/**
* Parses a string into a {@link LineNumberMap}.
* The string is produced by {@link #exportMap()}.
* @param input the input string
*/
public static LineNumberMap importMap(String input) {
StringTokenizer st = new QuotedStringTokenizer(input, " ", "\"\'", '\\', true);
String s = st.nextToken("{}");
assert (s.equals("F"));
ArrayList<String> strings = importStringMap(st);
LineNumberMap res = new LineNumberMap(strings);
if (!st.hasMoreTokens())
return res;
s = st.nextToken("{}");
assert (s.equals(" L"));
s = st.nextToken();
assert (s.equals("{"));
while (st.hasMoreTokens()) {
String t = st.nextToken(":}");
if (t.equals("}"))
break;
int n = Integer.parseInt(t);
t = st.nextToken();
assert (t.equals(":"));
int i = Integer.parseInt(st.nextToken("-"));
t = st.nextToken();
assert (t.equals("-"));
int e = Integer.parseInt(st.nextToken("-"));
t = st.nextToken(">");
assert (t.equals("-"));
t = st.nextToken(">");
assert (t.equals(">"));
int f = Integer.parseInt(st.nextToken(":"));
t = st.nextToken();
assert (t.equals(":"));
int l = Integer.parseInt(st.nextToken(","));
res.map.put(new Key(n, i, e), new Entry(f, l, -1));
t = st.nextToken();
assert (t.equals(","));
}
if (!st.hasMoreTokens())
return res;
s = st.nextToken("{}");
assert (s.equals(" M"));
s = st.nextToken();
assert (s.equals("{"));
while (st.hasMoreTokens()) {
String t = st.nextToken("-}");
if (t.equals("}"))
break;
MethodDescriptor md = MethodDescriptor.parse(t);
t = st.nextToken(">");
assert (t.equals("-"));
t = st.nextToken(">");
assert (t.equals(">"));
MethodDescriptor sm = MethodDescriptor.parse(st.nextToken(";"));
res.methods.put(md, sm);
t = st.nextToken();
assert (t.equals(";"));
}
assert (!st.hasMoreTokens());
return res;
}
/**
* Merges a set of new entries into a given map. Changes the map in place!
* @param map the target map (changed in place!)
* @param newEntries the set of new entries
*/
private static void mergeMap(LineNumberMap map, LineNumberMap newEntries) {
assert (map != null);
final LineNumberMap m = map;
final LineNumberMap n = newEntries;
for (Key p : n.map.keySet()) {
// assert (!m.map.containsKey(p));
Entry e = n.map.get(p);
m.put(n.lookupString(p.fileId), p.start_line, p.end_line, n.lookupString(e.fileId), e.line, e.column);
}
for (MethodDescriptor d : n.methods.keySet()) {
// if (m.methods.containsKey(d))
// assert (false) : d.toPrettyString(n)+" already present";
assert (!m.methods.containsKey(d)) : d.toPrettyString(n)+" already present";
MethodDescriptor e = n.methods.get(d);
assert (e.lines == null);
Key dk = new Key(m.stringId(n.lookupString(d.lines.fileId)), d.lines.start_line, d.lines.end_line);
MethodDescriptor dp = m.createMethodDescriptor(n.lookupString(d.container),
n.lookupString(d.name), n.lookupString(d.returnType), n.lookupStrings(d.args), dk);
MethodDescriptor ep = m.createMethodDescriptor(n.lookupString(e.container),
n.lookupString(e.name), n.lookupString(e.returnType), n.lookupStrings(e.args), null);
m.methods.put(dp, ep);
}
}
/**
* Merges a set of maps into a new map. Returns the new map.
* @param maps the set of maps to merge
* @return the newly-created map containing merged entries from maps
*/
public static LineNumberMap mergeMaps(LineNumberMap[] maps) {
LineNumberMap map = new LineNumberMap();
for (int i = 0; i < maps.length; i++) {
mergeMap(map, maps[i]);
}
return map;
}
private String[] allFiles() {
TreeSet<String> files = new TreeSet<String>();
for (Entry e : map.values()) {
files.add(lookupString(e.fileId));
}
return files.toArray(new String[files.size()]);
}
private static int findFile(String name, String[] files) {
// files is assumed sorted alphanumerically
return Arrays.binarySearch(files, name);
}
private static class CPPLineInfo {
public final int x10index;
public final int x10method;
public final int cppindex;
public final int x10line;
public final int x10column;
public final int cppfromline;
public final int cpptoline;
public final int fileId;
public CPPLineInfo(int x10index, int x10method, int cppindex, int x10line, int cppfromline, int cpptoline, int fileId, int x10column) {
this.x10index = x10index;
this.x10method = x10method;
this.cppindex = cppindex;
this.x10line = x10line;
this.x10column = x10column;
this.cppfromline = cppfromline;
this.cpptoline = cpptoline;
this.fileId = fileId;
}
public static Comparator<CPPLineInfo> byX10info() {
return new Comparator<CPPLineInfo>() {
public int compare(CPPLineInfo o1, CPPLineInfo o2) {
int index_d = o1.x10index - o2.x10index;
if (index_d != 0) return index_d;
return o1.x10line - o2.x10line;
}
};
}
public static Comparator<CPPLineInfo> byCPPinfo() {
return new Comparator<CPPLineInfo>() {
public int compare(CPPLineInfo o1, CPPLineInfo o2) {
int index_d = o1.cppindex - o2.cppindex;
if (index_d != 0) return index_d;
return o1.cppfromline - o2.cppfromline;
}
};
}
}
private class CPPMethodInfo implements Comparable<CPPMethodInfo> {
public final int x10class;
public final int x10method;
public final int x10rettype;
public final int[] x10args;
public final int cppclass;
public int cpplineindex;
public int lastX10Line;
public CPPMethodInfo(int x10class, int x10method, int x10rettype, int[] x10args, int cppclass, int lastX10Line) {
this.x10class = x10class;
this.x10method = x10method;
this.x10rettype = x10rettype;
this.x10args = x10args;
this.cppclass = cppclass;
this.lastX10Line = lastX10Line;
}
private String concatArgs() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < x10args.length; i++) {
sb.append(lookupString(x10args[i]));
}
return sb.toString();
}
public int compareTo(CPPMethodInfo o) {
int class_d = lookupString(x10class).compareTo(lookupString(o.x10class));
if (class_d != 0) return class_d;
int name_d = lookupString(x10method).compareTo(lookupString(o.x10method));
if (name_d != 0) return name_d;
return concatArgs().compareTo(o.concatArgs());
}
}
/**
* Generates code for the line number map as required by the Toronto C++
* Debugger backend into the specified stream.
* @param w the output stream
* @param m the map to export
*/
public void exportForCPPDebugger(ClassifiedStream w, LineNumberMap m) {
String debugSectionAttr = "__attribute__((_X10_DEBUG_SECTION))";
String debugDataSectionAttr = "__attribute__((_X10_DEBUG_DATA_SECTION))";
int size = m.size();
int offset = 0;
int[] offsets = new int[size];
// All strings, concatenated, with intervening nulls.
w.writeln("static const char _X10strings[] __attribute__((used)) "+debugDataSectionAttr+" =");
for (int i = 0; i < size; i++) {
offsets[i] = offset;
String s = m.lookupString(i);
w.writeln(" \""+StringUtil.escape(s)+"\\0\" //"+offsets[i]);
offset += s.length()+1;
}
w.writeln(" \"\";");
w.forceNewline();
if (!m.isEmpty()) {
String[] files = m.allFiles();
// A list of X10 source files that contributed to the generation of the current C++ file.
w.writeln("static const struct _X10sourceFile _X10sourceList[] __attribute__((used)) "+debugDataSectionAttr+" = {");
for (int i = 0; i < files.length; i++) {
w.write(" { ");
w.write(""+0+", "); // FIXME: _numLines
w.write(""+offsets[m.stringId(files[i])]); // _stringIndex
w.writeln(" },");
}
w.writeln("};");
w.forceNewline();
// // A cross reference of X10 statements to the first C++ statement.
// // Sorted by X10 file index and X10 source file line.
ArrayList<CPPLineInfo> x10toCPPlist = new ArrayList<CPPLineInfo>(m.map.size());
for (Key p : m.map.keySet()) {
Entry e = m.map.get(p);
x10toCPPlist.add(
new CPPLineInfo(findFile(m.lookupString(e.fileId), files), // _X10index
0, // FIXME: _X10method
offsets[p.fileId], // _CPPindex
e.line, // _X10line
p.start_line, // _CPPline
p.end_line,
p.fileId,
e.column)); // _X10column
}
Collections.sort(x10toCPPlist, CPPLineInfo.byX10info());
// remove items that have duplicate lines, leaving only the one with the earlier column
CPPLineInfo previousCppDebugInfo = x10toCPPlist.get(0);
for (int i=1; i<x10toCPPlist.size();)
{
CPPLineInfo cppDebugInfo = x10toCPPlist.get(i);
if (cppDebugInfo.x10line == previousCppDebugInfo.x10line)
{
if (cppDebugInfo.x10column > previousCppDebugInfo.x10column)
x10toCPPlist.remove(i); // keep the previous one, delete this one
else
{
// keep this one, delete the previous one
x10toCPPlist.remove(i-1);
previousCppDebugInfo = cppDebugInfo;
}
}
else
{
previousCppDebugInfo = cppDebugInfo;
i++;
}
}
w.writeln("static const struct _X10toCPPxref _X10toCPPlist[] __attribute__((used)) "+debugDataSectionAttr+" = {");
for (CPPLineInfo cppDebugInfo : x10toCPPlist) {
w.write(" { ");
w.write(""+cppDebugInfo.x10index+", "); // _X10index
// w.write(""+cppDebugInfo.x10method+", "); // _X10method
w.write(""+cppDebugInfo.cppindex+", "); // _CPPindex
w.write(""+cppDebugInfo.x10line+", "); // _X10line
w.write(""+cppDebugInfo.cppfromline+", "); // _CPPFromLine
w.write(""+cppDebugInfo.cpptoline); // _CPPtoLine
w.writeln(" },");
}
w.writeln("};");
w.forceNewline();
// A list of the X10 method names.
// Sorted by X10 method name.
ArrayList<CPPMethodInfo> x10MethodList = new ArrayList<CPPMethodInfo>(m.methods.size());
Map<Key, CPPMethodInfo> keyToMethod = CollectionFactory.newHashMap();
for (MethodDescriptor md : m.methods.keySet()) {
MethodDescriptor sm = m.methods.get(md);
final CPPMethodInfo cmi = m.new CPPMethodInfo(sm.container, // _x10class
sm.name, // _x10method
sm.returnType, // _x10returnType
sm.args, // _x10args
md.container, // _cppClass
sm.lines.end_line); // _lastX10Line
x10MethodList.add(cmi);
keyToMethod.put(md.lines, cmi);
}
// A cross reference of C++ statements to X10 statements.
// Sorted by C++ file index and C++ source file line.
// A line range is used to minimize the storage required.
ArrayList<CPPLineInfo> cpptoX10xrefList = new ArrayList<CPPLineInfo>(m.map.size());
for (Key p : m.map.keySet()) {
Entry e = m.map.get(p);
cpptoX10xrefList.add(
new CPPLineInfo(findFile(m.lookupString(e.fileId), files), // _X10index
0, // FIXME: _X10method
offsets[p.fileId], // _CPPindex
e.line, // _X10line
p.start_line, // _CPPfromline
p.end_line, // _CPPtoline
p.fileId,
e.column));
}
Collections.sort(cpptoX10xrefList, CPPLineInfo.byCPPinfo());
w.writeln("static const struct _CPPtoX10xref _CPPtoX10xrefList[] __attribute__((used)) "+debugDataSectionAttr+" = {");
int i = 0;
for (CPPLineInfo cppDebugInfo : cpptoX10xrefList) {
w.write(" { ");
w.write(""+cppDebugInfo.x10index+", "); // _X10index
// w.write(""+cppDebugInfo.x10method+", "); // _X10method
w.write(""+cppDebugInfo.cppindex+", "); // _CPPindex
w.write(""+cppDebugInfo.x10line+", "); // _X10line
w.write(""+cppDebugInfo.cppfromline+", "); // _CPPfromline
w.write(""+cppDebugInfo.cpptoline); // _CPPtoline
w.writeln(" },");
Key k = new Key(cppDebugInfo.fileId, cppDebugInfo.cppfromline, cppDebugInfo.cpptoline);
CPPMethodInfo methodInfo = keyToMethod.get(k);
if (methodInfo != null) {
methodInfo.cpplineindex = i; // _lineIndex
}
i++;
}
w.writeln("};");
w.forceNewline();
if (!m.methods.isEmpty()) {
Collections.sort(x10MethodList);
// FIXME: Cannot put _X10methodNameList in debugDataSectionAttr, because it's not constant
// (the strings cause static initialization for some reason)
w.writeln("static const struct _X10methodName _X10methodNameList[] __attribute__((used)) = {");
w.writeln("#if defined(__xlC__)");
for (CPPMethodInfo cppMethodInfo : x10MethodList) {
w.write(" { ");
w.write(""+offsets[cppMethodInfo.x10class]+", "); // _x10class
w.write(""+offsets[cppMethodInfo.x10method]+", "); // _x10method
w.write(""+offsets[cppMethodInfo.x10rettype]+", "); // _x10returnType
w.write(""+offsets[cppMethodInfo.cppclass]+", "); // _cppClass
w.write("(uint64_t) 0, "); // TODO - this needs to be re-designed, with the debugger team
w.write(""+cppMethodInfo.x10args.length+", "); // _x10argCount
w.write(""+cppMethodInfo.cpplineindex+", "); // _lineIndex
w.write(""+cppMethodInfo.lastX10Line); // _lastX10Line
w.writeln(" }, // "+m.lookupString(cppMethodInfo.x10class)+'.'+m.lookupString(cppMethodInfo.x10method)+"()");
}
w.writeln("#else");
for (CPPMethodInfo cppMethodInfo : x10MethodList) {
w.write(" { ");
w.write(""+offsets[cppMethodInfo.x10class]+", "); // _x10class
w.write(""+offsets[cppMethodInfo.x10method]+", "); // _x10method
w.write(""+offsets[cppMethodInfo.x10rettype]+", "); // _x10returnType
w.write(""+offsets[cppMethodInfo.cppclass]+", "); // _cppClass
w.write("(uint64_t) ");
for (i = 0; i < cppMethodInfo.x10args.length; i++) {
int a = cppMethodInfo.x10args[i];
w.write("\""+encodeIntAsChars(offsets[a])+"\" "); // _x10args
}
w.write("\"\", ");
w.write(""+cppMethodInfo.x10args.length+", "); // _x10argCount
w.write(""+cppMethodInfo.cpplineindex+", "); // _lineIndex
w.write(""+cppMethodInfo.lastX10Line); // _lastX10Line
w.writeln(" }, // "+m.lookupString(cppMethodInfo.x10class)+'.'+m.lookupString(cppMethodInfo.x10method)+"()");
}
w.writeln("#endif");
w.writeln("};");
w.forceNewline();
}
// variable map stuff
if (localVariables != null)
{
w.writeln("static const struct _X10LocalVarMap _X10variableNameList[] __attribute__((used)) "+debugDataSectionAttr+" = {");
for (LocalVariableMapInfo v : localVariables)
{
int typeIndex = 0;
// convert types from simple names to memberVariable table indexes.
if (v._x10type >= 101 && v._x10type <= 103)
{
if (memberVariables != null && memberVariables.containsKey(v._x10typeIndex))
{
int index = 0;
for (Integer classId : memberVariables.keySet())
{
if (classId == v._x10typeIndex)
{
typeIndex = index;
if (v._x10type==102 && "this".equals(m.lookupString(v._x10name)))
v._x10type=101; // hack requested by the debugger team
else
{
// convert the type to what's in the main table
ClassMapInfo cmi = memberVariables.get(classId);
v._x10type = cmi._type;
}
break;
}
else
index++;
}
}
else
typeIndex = offsets[v._x10typeIndex] * -1;
}
else if (v._x10type==100 || v._x10typeIndex==-2)
{
if (v._x10startLine == v._x10endLine) // skip generated closures
continue;
if (closureMembers != null)
{
int index = 0;
for (Integer classId : closureMembers.keySet())
{
ClassMapInfo value = closureMembers.get(classId);
if (value._x10startLine == v._x10startLine && value._x10endLine == v._x10endLine)
{
typeIndex = index;
break;
}
else if (value._x10startLine != value._x10endLine)
index++;
}
}
else
typeIndex = offsets[v._x10typeIndex] * -1;
}
else
typeIndex = v._x10typeIndex;
w.writeln(" { "+offsets[v._x10name]+", "+v._x10type+", "+typeIndex+", "+offsets[v._cppName]+", "+findFile(v._x10index, files)+", "+v._x10startLine+", "+v._x10endLine+" }, // "+m.lookupString(v._x10name));
}
w.writeln("};");
w.forceNewline();
}
if (memberVariables != null)
{
for (Integer classId : memberVariables.keySet())
{
String classname = m.lookupString(classId);
w.writeln("static const struct _X10TypeMember _X10"+classname.substring(classname.lastIndexOf('.')+1)+"Members[] __attribute__((used)) "+debugDataSectionAttr+" = {");
ClassMapInfo cmi = memberVariables.get(classId);
boolean someMembersWritten = false;
for (int j=0; j<cmi._members.size();)
{
MemberVariableMapInfo v = cmi._members.get(j);
boolean skip = false;
if (v._x10type >= 101 && v._x10type <= 103)
{
int index = 0;
for (Integer memberId : memberVariables.keySet())
{
if (memberId == v._x10typeIndex)
{
if ("{...}".equals(m.lookupString(v._x10memberName)) && (memberVariables.get(memberId)._members.size() == 0))
{
skip = true;
cmi._members.remove(j);
}
else
v._x10typeIndex = index;
break;
}
index++;
}
if (index >= memberVariables.size() && v._x10typeIndex > 0)
v._x10typeIndex = offsets[v._x10typeIndex] * -1;
}
if (!skip)
{
someMembersWritten = true;
w.writeln(" { "+v._x10type+", "+v._x10typeIndex+", "+offsets[v._x10memberName]+", "+offsets[v._cppMemberName]+", "+offsets[v._cppClass]+" }, // "+m.lookupString(v._x10memberName));
j++;
}
}
if (!someMembersWritten)
w.writeln("NULL };");
else
w.writeln("};");
w.forceNewline();
}
w.writeln("static const struct _X10ClassMap _X10ClassMapList[] __attribute__((used)) = {");
for (Integer classId : memberVariables.keySet())
{
String classname = m.lookupString(classId);
int stringIndex = offsets[classId];
if (classname.contains("__")) // remove the prefix from the name, for debugger display purposes
stringIndex = stringIndex+classname.lastIndexOf('_')+1;
w.writeln(" { "+memberVariables.get(classId)._type+", "+stringIndex+", sizeof("+classname.replace(".", "::")+"), "+memberVariables.get(classId)._members.size()+", _X10"+classname.substring(classname.lastIndexOf('.')+1)+"Members },");
}
w.writeln("};");
w.forceNewline();
}
if (closureMembers != null)
{
for (Integer classId : closureMembers.keySet())
{
String classname = m.lookupString(classId);
ClassMapInfo cmi = closureMembers.get(classId);
if (cmi._x10endLine != cmi._x10startLine) // this is a hack to skip generated closures
{
w.writeln("static const struct _X10TypeMember _X10"+classname.substring(classname.lastIndexOf('.')+1)+"Members[] __attribute__((used)) "+debugDataSectionAttr+" = {");
for (MemberVariableMapInfo v : cmi._members)
{
int typeIndex;
if (v._x10type >= 101 && v._x10type <= 103)
{
// see if this class is defined in our class mappings
typeIndex = -1;
if (memberVariables != null)
{
int index = 0;
for (Integer memberId : memberVariables.keySet())
{
if (memberId == v._x10typeIndex)
{
typeIndex = index;
break;
}
index++;
}
}
}
else
typeIndex = v._x10typeIndex;
w.writeln(" { "+v._x10type+", "+typeIndex+", "+offsets[v._x10memberName]+", "+offsets[v._cppMemberName]+", "+offsets[v._cppClass]+" }, // "+m.lookupString(v._x10memberName));
}
w.writeln("};");
w.forceNewline();
}
}
w.writeln("static const struct _X10ClosureMap _X10ClosureMapList[] __attribute__((used)) = {"); // inclusion of debugDataSectionAttr causes issues on Macos. See XTENLANG-2318.
boolean closureMembersWritten = false;
for (Integer classId : closureMembers.keySet())
{
String classname = m.lookupString(classId);
ClassMapInfo cmi = closureMembers.get(classId);
if (cmi._x10endLine != cmi._x10startLine)
{
closureMembersWritten = true;
w.writeln(" { "+cmi._type+", "+offsets[classId]+", sizeof("+cmi._sizeOfArg.replace(".", "::")+"), "+cmi._members.size()+", "+findFile(cmi._file, files)+", "+cmi._x10startLine +", "+cmi._x10endLine+", _X10"+classname.substring(classname.lastIndexOf('.')+1)+"Members },");
}
}
if (!closureMembersWritten)
w.writeln("NULL };");
else
w.writeln("};");
w.forceNewline();
}
}
if (!arrayMap.isEmpty())
{
w.writeln("static const struct _X10ArrayMap _X10ArrayMapList[] __attribute__((used)) "+debugDataSectionAttr+" = {");
Iterator<Integer> iterator = arrayMap.iterator();
while(iterator.hasNext())
{
int maintype = iterator.next();
int innertype = iterator.next();
if ((maintype >= 101 && maintype <= 103) && innertype != -1)
{
int lookingFor = innertype;
innertype = -1;
// see if this is a local class
if (memberVariables != null)
{
int index = 0;
for (Integer memberId : memberVariables.keySet())
{
if (memberId == lookingFor)
{
innertype = index;
// convert the type to what's in the main table
ClassMapInfo cmi = memberVariables.get(memberId);
maintype = cmi._type;
break;
}
index++;
}
}
}
w.writeln(" { "+maintype+", "+innertype+" },");
}
w.writeln("};");
w.forceNewline();
}
if (referenceMembers != null)
{
for (Integer classId : referenceMembers.keySet())
{
String classname = m.lookupString(classId);
ClassMapInfo cmi = referenceMembers.get(classId);
w.writeln("static const struct _X10TypeMember _X10Ref"+classname.substring(classname.lastIndexOf('.')+1)+"Members[] __attribute__((used)) "+debugDataSectionAttr+" = {");
for (MemberVariableMapInfo v : cmi._members)
w.writeln(" { "+v._x10type+", "+v._x10typeIndex+", "+offsets[v._x10memberName]+", "+offsets[v._cppMemberName]+", "+offsets[v._cppClass]+" }, // "+m.lookupString(v._x10memberName));
w.writeln("};");
w.forceNewline();
}
w.writeln("static const struct _X10ClassMap _X10RefMapList[] __attribute__((used)) = {"); // inclusion of debugDataSectionAttr causes issues on Macos. See XTENLANG-2318.
int index = 0;
for (Integer classId : referenceMembers.keySet())
{
String classname = m.lookupString(classId);
ClassMapInfo cmi = referenceMembers.get(classId);
w.writeln(" { "+cmi._type+", "+offsets[classId]+", sizeof("+cmi._sizeOfArg+"), "+cmi._members.size()+", _X10Ref"+classname.substring(classname.lastIndexOf('.')+1)+"Members },");
index++;
}
w.writeln("};");
w.forceNewline();
}
// A meta-structure that refers to all of the above
w.write("static const struct _MetaDebugInfo_t _MetaDebugInfo __attribute__((used)) "+debugSectionAttr+" = {");
w.newline(4); w.begin(0);
w.writeln("sizeof(struct _MetaDebugInfo_t),");
w.writeln("X10_META_LANG,");
w.writeln("0x0C091910, // 2012-09-25, 16:00"); // Format: "YYMMDDHH". One byte for year, month, day, hour.
w.writeln("sizeof(_X10strings),");
if (!m.isEmpty()) {
w.writeln("sizeof(_X10sourceList),");
w.writeln("sizeof(_X10toCPPlist),");
w.writeln("sizeof(_CPPtoX10xrefList),");
} else {
w.writeln("0,");
w.writeln("0,");
w.writeln("0,");
}
if (!m.methods.isEmpty()) {
w.writeln("sizeof(_X10methodNameList),");
} else {
w.writeln("0, // no member variable mappings");
}
if (!m.isEmpty() && localVariables != null)
w.writeln("sizeof(_X10variableNameList),");
else
w.writeln("0, // no local variable mappings");
if (!m.isEmpty() && memberVariables != null)
w.writeln("sizeof(_X10ClassMapList),");
else
w.writeln("0, // no class mappings");
if (closureMembers != null)
w.writeln("sizeof(_X10ClosureMapList),");
else
w.writeln("0, // no closure mappings");
if (!arrayMap.isEmpty())
w.writeln("sizeof(_X10ArrayMapList),");
else
w.writeln("0, // no array mappings");
if (referenceMembers != null)
w.writeln("sizeof(_X10RefMapList),");
else
w.writeln("0, // no reference mappings");
w.writeln("_X10strings,");
if (!m.isEmpty()) {
w.writeln("_X10sourceList,");
w.writeln("_X10toCPPlist,");
w.writeln("_CPPtoX10xrefList,");
} else {
w.writeln("NULL,");
w.writeln("NULL,");
w.writeln("NULL,");
}
if (!m.methods.isEmpty()) {
w.writeln("_X10methodNameList,");
m.methods.clear();
} else {
w.writeln("NULL,");
}
if (localVariables != null)
{
if (!m.isEmpty())
w.writeln("_X10variableNameList,");
else
w.writeln("NULL,");
localVariables.clear();
localVariables = null;
}
else
w.writeln("NULL,");
if (!m.isEmpty() && memberVariables != null)
{
w.writeln("_X10ClassMapList,");
memberVariables.clear();
memberVariables = null;
}
else
w.writeln("NULL,");
if (closureMembers != null)
{
w.writeln("_X10ClosureMapList,");
closureMembers.clear();
closureMembers = null;
}
else
w.writeln("NULL,");
if (!arrayMap.isEmpty())
{
arrayMap.clear();
w.writeln("_X10ArrayMapList,");
}
else
w.writeln("NULL,");
if (referenceMembers != null)
{
referenceMembers.clear();
referenceMembers = null;
w.write("_X10RefMapList");
}
else
w.write("NULL");
w.end(); w.newline();
w.writeln("};");
if (loopVariables != null)
{
loopVariables.clear();
loopVariables = null;
}
}
private static String encodeIntAsChars(int i) {
String b1 = "\\"+Integer.toOctalString((i >> 24) & 0xFF);
String b2 = "\\"+Integer.toOctalString((i >> 16) & 0xFF);
String b3 = "\\"+Integer.toOctalString((i >> 8) & 0xFF);
String b4 = "\\"+Integer.toOctalString((i >> 0) & 0xFF);
return b1+b2+b3+b4;
}
}