/* * 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.visit; import static x10cpp.visit.ASTQuery.getCppBoxRep; import static x10cpp.visit.ASTQuery.getCppRep; import static x10cpp.visit.SharedVarsMethods.CONSTRUCTOR; import static x10cpp.visit.SharedVarsMethods.DESERIALIZATION_BUFFER; import static x10cpp.visit.SharedVarsMethods.DESERIALIZER_METHOD; import static x10cpp.visit.SharedVarsMethods.DESERIALIZE_BODY_METHOD; import static x10cpp.visit.SharedVarsMethods.DESERIALIZE_METHOD; import static x10cpp.visit.SharedVarsMethods.SAVED_THIS; import static x10cpp.visit.SharedVarsMethods.SERIALIZATION_BUFFER; import static x10cpp.visit.SharedVarsMethods.SERIALIZATION_ID_FIELD; import static x10cpp.visit.SharedVarsMethods.SERIALIZE_BODY_METHOD; import static x10cpp.visit.SharedVarsMethods.SERIALIZE_ID_METHOD; import static x10cpp.visit.SharedVarsMethods.SERIALIZE_METHOD; import static x10cpp.visit.SharedVarsMethods.THIS; import static x10cpp.visit.SharedVarsMethods.chevrons; import static x10cpp.visit.SharedVarsMethods.make_ref; import static x10cpp.visit.SharedVarsMethods.make_captured_lval; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import polyglot.ast.Call_c; import polyglot.ast.ConstructorDecl_c; import polyglot.ast.Expr; import polyglot.ast.FieldDecl_c; import polyglot.ast.Formal; import polyglot.ast.Formal_c; import polyglot.ast.LocalDecl_c; import polyglot.ast.Local_c; import polyglot.ast.New_c; import polyglot.ast.Node; import polyglot.ast.Receiver; import polyglot.ast.TypeNode; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.Context; import polyglot.types.FieldInstance; import polyglot.types.Flags; import polyglot.types.Def; import polyglot.types.Name; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.Types; import polyglot.types.VarDef; import polyglot.types.VarInstance; import polyglot.util.CodeWriter; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; import polyglot.util.ErrorInfo; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.util.StringUtil; import polyglot.visit.Translator; import x10.ast.X10ClassDecl_c; import x10.ast.X10MethodDecl_c; import x10.ast.X10Special; import x10.ast.X10Special_c; import x10.constraint.XField; import x10.constraint.XLit; import x10.constraint.XVar; import x10.errors.Warnings; import x10.extension.X10Ext; import x10.types.ClosureDef; import x10.types.ConstrainedType; import x10.types.FunctionType; import x10.types.ParameterType; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10ConstructorDef; import x10.types.X10FieldDef; import x10.types.X10FieldInstance; import x10.types.X10LocalDef; import x10.types.X10MethodDef; import x10.types.MethodInstance; import x10.types.constraints.CConstraint; import x10.types.constraints.CField; import polyglot.types.TypeSystem; import polyglot.types.TypeSystem_c.BaseTypeEquals; import x10.visit.StaticNestedClassRemover; import x10.visit.X10PrettyPrinterVisitor; import x10.util.ClassifiedStream; import x10.util.StreamWrapper; import x10cpp.X10CPPCompilerOptions; import x10cpp.debug.LineNumberMap; import x10cpp.types.X10CPPContext_c; public class Emitter { private final Translator tr; private ASTQuery query; public Emitter(Translator tr) { this.tr = tr; query = new ASTQuery(tr); } private static final String[] CPP_KEYWORDS = { // Some are also X10 keywords "asm", "auto", "bool", "break", "case", "catch", "char", "class", "const", "const_cast", "continue", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "operator", "private", "protected", "public", "register", "reinterpret_cast", "return", "restrict", // Yes, stupid xlC has a "restrict" keyword -- who knew? "short", "signed", "sizeof", "static", "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", // operator names "and", "and_eq", "not", "not_eq", "or", "or_eq", "xor", "xor_eq", "bitand", "bitor", "compl", // X10 types "x10_boolean", "x10_byte", "x10_char", "x10_short", "x10_int", "x10_long", "x10_float", "x10_double", // X10 implementation names "FMGL", "TPMGL", "TYPENAME", "getRTT", "rtt", "RTT_H_DECLS", "RTT_CC_DECLS1", // macros defined by the C++ implementation "i386", // Additionally, anything starting with a '_' is reserved, and may clash }; private static boolean isCPPKeyword(String name) { for (int i = 0; i < CPP_KEYWORDS.length; i++) { if (CPP_KEYWORDS[i].equals(name)) return true; } return false; } private static String mangle_to_cpp(String str) { str = x10.emitter.Emitter.mangleIdentifier(str); str = StringUtil.escape(str, true); if (isCPPKeyword(str)) str = "_kwd__" + str; return str.replace("$", "__").replace("\\", "__"); } public static String mangled_method_name(String str) { return mangle_to_cpp(str); } public static String mangled_non_method_name(String str) { return mangle_to_cpp(str); } public static String mangled_field_name(String str) { //return "__"+mangle_to_cpp(str); //return "x10__"+mangle_to_cpp(str); return "FMGL("+mangle_to_cpp(str)+")"; } public static String mangled_parameter_type_name(String str) { return "TPMGL("+mangle_to_cpp(str)+")"; } /** * Same as n.printBlock(child, w, tr); but without the enterScope call. */ void printBlock(Node n, Expr child, StreamWrapper w, Translator tr) { w.begin(0); child.del().translate(w, tr); w.end(); } /** * Translate the string representation of a fully-qualified type name. * TODO: rewrite to use QName instead */ public static String translateFQN(String name) { return translateFQN(name, "::"); } public static String translateFQN(String name, String delim) { return name.replace("$","__").replaceAll("\\.", delim); } public static String translate_mangled_FQN(String name) { return translate_mangled_FQN(name, "::"); } public static String translate_mangled_FQN(String name, String delim) { String src = name; String dest = ""; int fromIndex = 0; while (true) { boolean finished=false; int toIndex = src.indexOf('.', fromIndex); if (toIndex < 0){ finished=true; toIndex=src.length(); } String s = src.substring(fromIndex, toIndex); dest += mangled_non_method_name(s); if (finished) break; dest += "."; fromIndex = toIndex+1; } return translateFQN(dest, delim); } public static String translate_mangled_NSFQN(String name) { // namespace FQN String src = name; String dest = ""; int fromIndex = 0; while (true) { int toIndex = src.indexOf('.', fromIndex); if (fromIndex != 0 && toIndex >= 0) dest += "."; if (toIndex < 0) break; String s = src.substring(fromIndex, toIndex); dest += mangled_non_method_name(s); fromIndex = toIndex+1; } return translateFQN(dest); } /** * Print a type as a reference. */ void printType(Type type, CodeWriter w) { printType(type,w,null); } void printType(Type type, CodeWriter w, Context ctx) { w.write(translateType(type, true, ctx)); } /** * Translate a type name. */ public static String translateType(Type type) { return translateType(type, false); } /** * Return the full name of the type, taking into account nested class mangling. * @param ct the type * @return the full name of the type */ public static QName fullName(X10ClassType ct) { QName full; if (ct.def().isNested()) { // This is a legitimate case. We do not invoke StaticNestedClassRemover on // classes for which we don't generate code. Thus, while we cannot see a // definition of a nested class, we may well see references to such classes. // At the moment, we cannot make sure that StaticNestedClassRemover runs on // all classes - when we can, we should re-enable this assert. Name mangled = StaticNestedClassRemover.mangleName(ct.def()); QName pkg = ct.package_() != null ? ct.package_().fullName() : null; full = QName.make(pkg, mangled); } else full = ct.fullName(); return full; } private static HashMap<String,String> exploreConstraints(Context context, ConstrainedType type) { HashMap<String,String> r = new HashMap<String,String>(); CConstraint cc = type.getRealXClause(); // FIXME: [DC] context.constraintProjection ought not to eliminate information but it seems to? CConstraint projected = cc; //context.constraintProjection(cc); if (!projected.consistent()) return r; for (XVar xvar : projected.vars()) { XVar prefixes[] = xvar.vars(); if (prefixes.length!=2) continue; if (!prefixes[0].toString().equals("self")) continue; if (!(xvar instanceof CField)) continue; CField xvarf = (CField)xvar; // [DC] I believe that since we are only looking at constraints of the form self.f, // there is no need to check the type of the class which this field is attached to as it will // always be the type we are translating. if (!(xvarf.field() instanceof X10FieldDef)) continue; // only support # within @Native on property fields, not methods String property_name = ((X10FieldDef)xvarf.field()).name().toString(); // resolve to another variable, keep going XVar closed_xvar = projected.bindingForVar(xvar); if (closed_xvar!=null && closed_xvar instanceof XLit) { r.put(property_name, closed_xvar.toString()); } } return r; } static String baseName(FunctionType ft, boolean pkg) { String name = pkg ? "x10.lang." : ""; List<Type> args = ft.argumentTypes(); Type ret = ft.returnType(); if (ret.isVoid()) { name += "VoidFun"; } else { name += "Fun"; } name += "_" + ft.typeParameters().size(); name += "_" + args.size(); return name; } /** * Translate a type. * * @param type type to translate * @param asRef whether to make a reference * @return a string representation of the type */ public static String translateType(Type type, boolean asRef) { return translateType(type, asRef, null); } public static String translateType(Type type_, boolean asRef, Context ctx) { assert (type_ != null); TypeSystem xts = type_.typeSystem(); Type type = xts.expandMacros(type_); if (type.isVoid()) { return "void"; } HashMap<String,String> propertyKnowledge = null; if (ctx!=null && type instanceof ConstrainedType) propertyKnowledge = exploreConstraints(ctx, (ConstrainedType)type); // TODO: handle closures // if (((X10TypeSystem) type.typeSystem()).isClosure(type)) // return translateType(((X10Type) type).toClosure().base(), asRef); type = Types.baseType(type); String name = null; if (type instanceof FunctionType) { FunctionType ft = (FunctionType) type; List<Type> args = ft.argumentTypes(); name = translate_mangled_FQN(baseName(ft, true)); String typeArgs = ""; boolean firstArg = true; for (Type argType : args) { typeArgs += (firstArg ? "" : ", ")+translateType(argType, true); firstArg = false; } if (!ft.returnType().isVoid()) { typeArgs += (firstArg ? "" : ", ")+translateType(ft.returnType(), true); firstArg = false; } if (typeArgs.length() != 0) { name += chevrons(typeArgs); } } else if (type.isClass()) { X10ClassType ct = (X10ClassType) type.toClass(); if (ct.isX10Struct()) { // Struct types are not boxed up as Refs. They are always generated as just C++ class types // (Note: not pointer to Class, but the actual class). asRef = false; } List<Type> typeArguments = ct.typeArguments(); X10ClassDef cd = ct.x10Def(); if (typeArguments == null) typeArguments = new ArrayList<Type>(cd.typeParameters()); if (ct.isAnonymous()) { if (ct.interfaces().size() == 1 && ct.interfaces().get(0) instanceof FunctionType) { return translateType(ct.interfaces().get(0), asRef); } else { assert false : "unexpected anonymous type " + ct; assert ct.superClass() != null; return translateType(ct.superClass(), asRef); } } else { String pat = asRef ? getCppRep(cd) : getCppBoxRep(cd); if (pat != null) { Map<String, Object> env = new HashMap<String,Object>(); int counter=0; env.put(Integer.toString(counter++), type); Iterator<ParameterType> params = cd.typeParameters().iterator(); for (Type a : typeArguments) { env.put(params.next().name().toString(), a); env.put(Integer.toString(counter++), a); } if (propertyKnowledge!=null) for (String key : propertyKnowledge.keySet()) { env.put(key, propertyKnowledge.get(key)); } return nativeSubst("NativeRep", env, pat); } else { name = fullName(ct).toString(); } } name = translate_mangled_FQN(name); if (typeArguments.size() != 0) { String args = ""; int s = typeArguments.size(); for (Type t: typeArguments) { args += translateType(t, true); // type arguments are always translated as refs if (--s > 0) args +=", "; } name += chevrons(args); } } else if (type instanceof ParameterType) { name = ((ParameterType)type).name().toString(); return mangled_parameter_type_name(name); // parameter types shouldn't be refs } else if (type.isNull()) { return asRef ? "x10::lang::NullType*" : "x10::lang::NullType"; } else { assert false : type; // unhandled type. } assert (name != null); if (!asRef) return name; return make_ref(name); } void printArgumentList(CodeWriter w, X10CPPContext_c c) { printArgumentList(w, c, false, true); } void printArgumentList(CodeWriter w, X10CPPContext_c c, boolean omitType) { printArgumentList(w, c, omitType, true); } void printArgumentList(CodeWriter w, X10CPPContext_c c, boolean omitType, boolean saved_this_mechanism) { for (int i = 0; i < c.variables.size(); i++) { if (i > 0) { w.write(","); w.allowBreak(2, " "); } VarInstance<?> var = c.variables.get(i); if (!omitType) { Type t = var.type(); String type = translateType(t, true); w.write(type + " "); } String name = var.name().toString(); if (saved_this_mechanism && name.equals(THIS)) name = SAVED_THIS; else name = mangled_non_method_name(name) ; w.write(name); } } public void printTemplateSignature(List<? extends Type> list, CodeWriter h) { int size = list == null ? 0 : list.size(); if (size != 0) { h.write("template<class "); for (Type t: list) { assert (t instanceof ParameterType); h.write(translateType(t)); size--; if (size > 0) h.write(", class "); } h.write(">"); h.allowBreak(0, " "); } } void printTemplateInstantiation(MethodInstance mi, CodeWriter w) { if (mi.typeParameters().size() == 0) return; w.write("<"); for (Iterator<Type> i = mi.typeParameters().iterator(); i.hasNext(); ) { final Type at = i.next(); w.write(translateType(at, true)); if (i.hasNext()) { w.write(","); w.allowBreak(0, " "); } } w.write(" >"); } public static String voidTemplateInstantiation(int num) { if (num <= 0) return ""; StringBuffer b = new StringBuffer(); b.append("<"); for (int i = 0; i < num; i++) { if (i > 0) b.append(", "); b.append("void"); } b.append(">"); return b.toString(); } static MethodInstance getOverridingMethod(TypeSystem xts, ClassType thisClass, ClassType localClass, MethodInstance mi, Context context) { try { List<Type> params = ((MethodInstance) mi).typeParameters(); List<MethodInstance> overrides = xts.findAcceptableMethods(localClass, xts.MethodMatcher(thisClass, mi.name(), ((MethodInstance) mi).typeParameters(), mi.formalTypes(), context)); for (MethodInstance smi : overrides) { if (CollectionUtil.allElementwise(mi.formalTypes(), smi.formalTypes(), new BaseTypeEquals(context))) { List<Type> sparams = smi.typeParameters(); if (params == null && sparams == null) return smi; if (params != null && params.equals(sparams)) return smi; } } return null; } catch (SemanticException e) { return null; } } Type findRootMethodReturnType(X10MethodDef n, Position pos, MethodInstance from) { assert from != null; // [IP] Optimizations Flags flags = from.flags(); if (flags.isStatic() || flags.isPrivate() || flags.isProperty() || from.returnType().isVoid()) return from.returnType(); // [DC] c++ doesn't allow covariant smartptr return types so // we are forced to use the same type everywhere and cast // on call. This function gets the one type that we use for // all return types, from the root of the class hierarchy. // TODO: currently we cannot handle the following code: // A new approach is required. /* interface Cloneable { def clone() : Cloneable; } interface Cloneable2 { def clone() : Cloneable2; } class A implements Cloneable, Cloneable2 { public def clone() { return this; } } */ // [DC] TODO: There has to be a better way! TypeSystem xts = (TypeSystem) tr.typeSystem(); Context context = tr.context(); X10ClassType classType = (X10ClassType) from.container(); X10ClassType superClass = (X10ClassType) Types.baseType(classType.superClass()); List<Type> interfaces = classType.interfaces(); Type returnType = null; if (superClass != null) { MethodInstance superMeth = getOverridingMethod(xts,classType,superClass, from,context); if (superMeth != null) { //System.out.println(from+" overrides "+superMeth); returnType = findRootMethodReturnType(n, pos, superMeth); } } for (Type itf : interfaces) { X10ClassType itf_ = (X10ClassType) Types.baseType(itf); // same thing again for interfaces MethodInstance superMeth = getOverridingMethod(xts,itf_, itf_,from,context); if (superMeth != null) { //System.out.println(from+" implements "+superMeth); Type newReturnType = findRootMethodReturnType(n, pos, superMeth); // check -- if (returnType != null && !xts.typeDeepBaseEquals(returnType, newReturnType, context)) { String msg = "Two supertypes declare " + from + " with " + "different return types: " + returnType + " != " + newReturnType; Warnings.issue(tr.job(), msg, pos); } returnType = newReturnType; } } // if we couldn't find an overridden method, just use the local return type return returnType != null ? returnType : from.returnType(); } private static final QName NORETURN_ANNOTATION = QName.make("x10.compiler.NoReturn"); void printHeader(X10MethodDecl_c n, CodeWriter h, Translator tr, boolean qualify, boolean inlineDirective) { printHeader(n, h, tr, n.name().id().toString(), n.returnType().type(), qualify, inlineDirective); } public void printHeader(X10MethodDecl_c n, CodeWriter h, Translator tr, String name, Type ret, boolean qualify, boolean inlineDirective) { Flags flags = n.flags().flags(); X10MethodDef def = (X10MethodDef) n.methodDef(); MethodInstance mi = (MethodInstance) def.asInstance(); X10ClassType container = (X10ClassType) mi.container(); boolean nonVirtualDispatch = flags.isStatic() || container.isX10Struct() || flags.isProperty() || flags.isPrivate(); boolean genericVirtual = !nonVirtualDispatch && def.typeParameters().size() > 0; h.begin(0); if (qualify) { printTemplateSignature(((X10ClassType)Types.get(n.methodDef().container())).x10Def().typeParameters(), h); } if (inlineDirective) { h.write("inline "); } printTemplateSignature(def.typeParameters(), h); if (!qualify) { if (flags.isStatic()) { h.write(flags.retain(Flags.STATIC).translateJava()); } else if (!(nonVirtualDispatch || genericVirtual)) { h.write("virtual "); } } printType(ret, h); h.allowBreak(2, 2, " ", 1); if (qualify) { h.write(translateType(container)+ "::"); } h.write(mangled_method_name(name)); printFormalDecls(n, h, tr, flags, container); if (!qualify) { boolean noReturnPragma = false; try { TypeSystem xts = (TypeSystem)tr.typeSystem(); Type annotation = xts.systemResolver().findOne(NORETURN_ANNOTATION); if (!((X10Ext) n.ext()).annotationMatching(annotation).isEmpty()) { noReturnPragma = true; } } catch (SemanticException e) { /* Ignore exception when looking for annotation */ } if (noReturnPragma) { h.write(" X10_PRAGMA_NORETURN "); } } h.end(); if (!qualify) { if (n.body() == null && !flags.isProperty() && !container.isX10Struct() && !flags.isNative()) h.write(" = 0"); } } private void printFormalDecls(X10MethodDecl_c n, CodeWriter h, Translator tr, Flags flags, X10ClassType container) { h.write("("); h.allowBreak(2, 2, "", 0); h.begin(0); for (Iterator<Formal> i = n.formals().iterator(); i.hasNext(); ) { Formal f = i.next(); n.print(f, h, tr); if (i.hasNext()) { h.write(","); h.allowBreak(0, " "); } } h.end(); h.write(")"); } void printHeader(Formal_c n, CodeWriter h, Translator tr, boolean qualify) { // Flags flags = n.flags().flags(); h.begin(0); // if (flags.isFinal()) // h.write("const "); printType(n.type().type(), h, tr.context()); h.write(" "); TypeSystem xts = (TypeSystem) tr.typeSystem(); Type param_type = n.type().type(); param_type = Types.baseType(param_type); if (param_type instanceof X10ClassType) { X10ClassType c = (X10ClassType)param_type; if (c.isX10Struct()) { try { Type annotation = xts.systemResolver().findOne(QName.make("x10.compiler.ByRef")); if (!c.annotationsMatching(annotation).isEmpty()) h.write("&"); } catch (SemanticException e) { assert false : e; } } } h.write(mangled_non_method_name(n.name().id().toString())); h.end(); } private void printAllTemplateSignatures(X10ClassDef cd, CodeWriter h) { if (cd.isNested()) { assert (false) : ("Nested class alert!"); printAllTemplateSignatures((X10ClassDef) Types.get(cd.outer()), h); } printTemplateSignature(cd.typeParameters(), h); } void printRTTDefn(X10ClassType ct, StreamWrapper sw) { TypeSystem xts = ct.typeSystem(); X10ClassDef cd = ct.x10Def(); String x10name = fullName(ct).toString().replace('$','.'); int numParents = 0; if (ct.superClass() != null) { numParents++; } numParents += ct.interfaces().size(); String kind; if (ct.isX10Struct()) { kind = "x10aux::RuntimeType::struct_kind"; } else if (ct.flags().isInterface()) { kind = "x10aux::RuntimeType::interface_kind"; } else { kind = "x10aux::RuntimeType::class_kind"; } ClassifiedStream cs; if (cd.typeParameters().isEmpty()) { cs = sw.body(); boolean first = true; cs.writeln("x10aux::RuntimeType "+translateType(ct)+"::rtt;"); cs.write("void "+translateType(ct)+"::_initRTT() {"); cs.newline(4); cs.begin(0); cs.writeln("if (rtt.initStageOne(&rtt)) return;"); if (numParents > 0) { cs.write("const x10aux::RuntimeType* parents["+numParents+"] = { "); if (ct.superClass() != null) { cs.write("x10aux::getRTT" + chevrons(translateType(ct.superClass())) + "()"); first = false; } for (Type iface : ct.interfaces()) { if (!first) cs.write(", "); cs.write("x10aux::getRTT"+chevrons(translateType(iface))+"()"); first = false; } cs.writeln("};"); } else { cs.writeln("const x10aux::RuntimeType** parents = NULL; "); } cs.write("rtt.initStageTwo(\""+x10name+"\","+kind+", "+numParents+ ", parents, 0, NULL, NULL);"); if (ct.isX10Struct() && isPointerless(ct)) { cs.newline(); cs.write("rtt.containsPtrs = false;"); } cs.end(); cs.newline(); cs.write("}"); cs.newline(); } else { cs = sw.header(); boolean first = true; int numTypeParams = cd.typeParameters().size(); printTemplateSignature(cd.typeParameters(), cs); cs.writeln("x10aux::RuntimeType "+translateType(ct)+"::rtt;"); printTemplateSignature(cd.typeParameters(), cs); cs.write("void "+translateType(ct)+"::_initRTT() {"); cs.newline(4); cs.begin(0); cs.writeln("const x10aux::RuntimeType *canonical = x10aux::getRTT"+chevrons(translateType(MessagePassingCodeGenerator.getStaticMemberContainer(cd), false))+"();"); cs.writeln("if (rtt.initStageOne(canonical)) return;"); if (numParents > 0) { cs.write("const x10aux::RuntimeType* parents["+numParents+"] = { "); if (ct.superClass() != null) { cs.write("x10aux::getRTT" + chevrons(translateType(ct.superClass())) + "()"); first = false; } for (Type iface : ct.interfaces()) { if (!first) cs.write(", "); cs.write("x10aux::getRTT"+chevrons(translateType(iface))+"()"); first = false; } cs.writeln("};"); } else { cs.writeln("const x10aux::RuntimeType** parents = NULL; "); } cs.write("const x10aux::RuntimeType* params["+numTypeParams+"] = { "); first = true; for (Type param : cd.typeParameters()) { if (!first) cs.write(", "); cs.write("x10aux::getRTT"+chevrons(translateType(param))+"()"); first = false; } cs.writeln("};"); cs.write("x10aux::RuntimeType::Variance variances["+numTypeParams+"] = { "); first = true; for (ParameterType.Variance v : ct.x10Def().variances()) { if (!first) cs.write(", "); switch(v) { case COVARIANT: cs.write("x10aux::RuntimeType::covariant"); break; case CONTRAVARIANT: cs.write("x10aux::RuntimeType::contravariant"); break; case INVARIANT: cs.write("x10aux::RuntimeType::invariant"); break; default: assert false : "Unexpected Variance"; } first = false; } cs.writeln("};"); cs.writeln("const char *baseName = \""+x10name+"\";"); cs.write("rtt.initStageTwo(baseName, "+kind+", "+numParents+", parents, "+numTypeParams+", params, variances);"); cs.end(); cs.newline(); cs.writeln("}"); } cs.forceNewline(0); } // Helper method to recursively examine the fields of a struct and determine if they // are pointers. Used to mark the RTT of the struct as pointerless, thus enabling // Rails and Arrays of pointerless structs to be allocated with GC_MALLOC_ATOMIC private boolean isPointerless(X10ClassType ct) { assert ct.isX10Struct() : "Only structs should be checked to see if they are pointerless"; if (ASTQuery.getCppRep(ct.x10Def()) != null) return false; // be conservative on @NativeRep for (FieldInstance fi : ct.fields()) { if (fi.flags().isStatic()) continue; // ignore static fields; only care about instance fields if (!fi.type().isNumeric()) { if (fi.type().isClass() && ((X10ClassType)fi.type().toClass()).isX10Struct()) { // recursively check fields of struct type if (!isPointerless(((X10ClassType)fi.type().toClass()))) return false; } else { // if fi.type() isn't numeric and isn't a struct, it must be a pointer. return false; } } } return true; } void printHeader(X10ClassDecl_c n, CodeWriter h, Translator tr) { h.begin(0); // Handle generics // If it involves Parameter Types then generate C++ templates. printAllTemplateSignatures(n.classDef(), h); h.write("class "); assert (!n.classDef().isLocal()); if (n.classDef().isNested() && !n.classDef().isLocal()) { // FIXME: handle local classes assert (false) : ("Nested class alert!"); h.write(translateType(n.classDef().outer().get().asType()) + "::"); } h.write(mangled_non_method_name(n.name().id().toString())); if (!n.flags().flags().isInterface() && !n.classDef().isStruct()) { TypeNode sc = n.superClass(); if (sc == null) { h.write(" : public x10::lang::X10Class"); } else { String parent = translateType(n.superClass().type()); h.write(" : public "+parent); } } h.unifiedBreak(0); h.end(); } void printHeader(ConstructorDecl_c n, CodeWriter h, Translator tr, boolean define, boolean isMakeMethod, String rType) { Flags flags = n.flags().flags(); X10ClassType container = (X10ClassType) Types.get(n.constructorDef().container()); if (define){ printTemplateSignature(container.x10Def().typeParameters(), h); } // [IP] Constructors don't have type parameters, they inherit them from the container. //X10ConstructorDef def = (X10ConstructorDef) n.constructorDef(); //printTemplateSignature(toTypeList(def.typeParameters()), h); h.begin(0); String typeName = translateType(container.def().asType()); // not a virtual method, this function is called only when the static type is precise h.write(rType + " "); if (define) { h.write(typeName + "::"); } h.write((isMakeMethod ? SharedVarsMethods.MAKE : SharedVarsMethods.CONSTRUCTOR) + "("); h.allowBreak(2, 2, "", 0); h.begin(0); for (Iterator<Formal> i = n.formals().iterator(); i.hasNext(); ) { Formal f = i.next(); n.print(f, h, tr); if (i.hasNext()) { h.write(","); h.allowBreak(0, " "); } } h.end(); h.write(")"); h.end(); } void printHeader(FieldDecl_c n, CodeWriter h, Translator tr, boolean qualify) { Flags flags = n.flags().flags(); h.begin(0); if (!qualify) { if (flags.isStatic()) h.write(flags.retain(Flags.STATIC).translateJava()); } if (query.hasAnnotation(n, "x10.compiler.Volatile")) { h.write("volatile "); } printType(n.type().type(), h); h.allowBreak(2, 2, " ", 1); if (qualify) { X10ClassType declClass = (X10ClassType)n.fieldDef().asInstance().container().toClass(); h.write(translateType(declClass) + "::"); } h.write(mangled_field_name(n.name().id().toString())); h.end(); } void printHeader(LocalDecl_c n, CodeWriter h, Translator tr, boolean qualify) { //Flags flags = n.flags().flags(); h.begin(0); // Let us not generate constants - We will have problem in // initializing away from the place where it is declared. //if (flags.isFinal()) } // h.write("const "); if (tr.printType()) { assert (n != null); assert (n.type() != null); assert (n.type().type() != null); printType(n.type().type(), h, tr.context()); h.write(" "); } h.write(mangled_non_method_name(n.name().id().toString())); h.end(); } void enterClosure(X10CPPContext_c c) { c.advanceClosureId(); } void exitClosure(X10CPPContext_c c) { } void printExplicitTarget(Call_c n, Receiver target, X10CPPContext_c context, CodeWriter w) { if (target instanceof X10Special_c && ((X10Special_c)target).kind().equals(X10Special_c.THIS) && context.isInsideClosure()) { w.write(SAVED_THIS); if (context.isInsideClosure()) context.saveEnvVariableInfo(THIS); } else if (target instanceof Expr) { boolean assoc = !(target instanceof New_c); n.printSubExpr((Expr) target, assoc, w, tr); } else if (target != null) { n.print(target, w, tr); } return; } public void printDeclarationList(CodeWriter w, X10CPPContext_c c, List<VarInstance<?>> vars, List<VarInstance<?>> refs) { printDeclarationList(w, c, vars, true, false, refs); } void printDeclarationList(CodeWriter w, X10CPPContext_c c, List<VarInstance<?>> vars, boolean saved_this_mechanism, boolean writable, List<VarInstance<?>> refs) { for (int i = 0; i < vars.size(); i++) { VarInstance<?> var = vars.get(i); VarDef def = var.def(); Type t = var.type(); String type; if ((writable && !var.name().toString().equals(THIS)) || refs.contains(var)) { type = make_captured_lval(t); } else { type = translateType(t, true); } String name = var.name().toString(); if (saved_this_mechanism && name.equals(THIS)) { assert (c.isInsideClosure()); // FIXME: Krishna, why did you add this test? name = SAVED_THIS; } else { name = mangled_non_method_name(name); } w.write(type + " " + name + ";"); w.newline(); } } void generateClassSerializationMethods(ClassType type, StreamWrapper sw) { X10ClassType ct = (X10ClassType) type.toClass(); TypeSystem ts = type.typeSystem(); X10CPPContext_c context = (X10CPPContext_c) tr.context(); Type parent = type.superClass(); boolean customSerialization = type.isSubtype(ts.CustomSerialization(), context); ClassifiedStream w = sw.body(); ClassifiedStream h = sw.header(); h.forceNewline(); h.write("// Serialization"); h.newline(); String klass = translateType(type); String template = context.inTemplate() ? "template " : ""; if (!type.flags().isAbstract()) { // _serialization_id h.write("public: static const x10aux::serialization_id_t "+SERIALIZATION_ID_FIELD+";"); h.newline(); h.forceNewline(); printTemplateSignature(ct.x10Def().typeParameters(), w); w.write("const x10aux::serialization_id_t "+klass+"::"+SERIALIZATION_ID_FIELD+" = "); w.newline(4); w.write("x10aux::DeserializationDispatcher::addDeserializer("); w.write(klass+"::"+DESERIALIZER_METHOD+", x10aux::CLOSURE_KIND_NOT_ASYNC);"); w.newline(); w.forceNewline(); } // _serialize_id() if (!type.flags().isAbstract()) { h.write("public: "); if (!type.flags().isFinal()) h.write("virtual "); h.write("x10aux::serialization_id_t "+SERIALIZE_ID_METHOD+"() {"); h.newline(4); h.begin(0); h.write(" return "+SERIALIZATION_ID_FIELD+";"); h.end(); h.newline(); h.write("}"); h.newline(); h.forceNewline(); } if (customSerialization && !((X10ClassDef)ct.def()).hasDeserializationConstructor(context)) { h.writeln("// autogenerated custom deserialization"); h.writeln("void "+CONSTRUCTOR+"("+translateType(ts.SerialData(), true)+" sd) {"); h.newline(4); h.begin(0); h.write(translateType(parent)+"::"+CONSTRUCTOR+"(sd);"); h.end(); h.newline(); h.write("}"); h.newline(); h.forceNewline(); } // _serialize_body() h.write("public: "); h.write("virtual "); h.write("void "+SERIALIZE_BODY_METHOD+"("+SERIALIZATION_BUFFER+"& buf);"); h.newline(0); h.forceNewline(); printTemplateSignature(ct.x10Def().typeParameters(), w); w.write("void "+klass+"::"+SERIALIZE_BODY_METHOD+ "("+SERIALIZATION_BUFFER+"& buf) {"); w.newline(4); w.begin(0); if (customSerialization) { w.writeln("/* NOTE: Implements x10.io.CustomSerialization */"); w.writeln("buf.write(this->serialize());"); } else { if (parent != null && parent.isClass()) { w.write(translateType(parent)+"::"+SERIALIZE_BODY_METHOD+"(buf);"); w.newline(); } for (int i = 0; i < type.fields().size(); i++) { if (i != 0) w.newline(); FieldInstance f = (FieldInstance) type.fields().get(i); if (f instanceof X10FieldInstance && !query.ifdef(((X10FieldInstance) f).x10Def())) continue; if (f.flags().isStatic() || query.isSyntheticField(f.name().toString())) continue; if (f.flags().isTransient()) // don't serialize transient fields continue; String fieldName = mangled_field_name(f.name().toString()); w.write("buf.write(this->"+fieldName+");"); w.newline(); } } w.end(); w.newline(); w.write("}"); w.newline(); w.forceNewline(); if (!type.flags().isAbstract()) { // _deserializer() h.write("public: static "); h.write(make_ref("x10::lang::Reference")+" "+DESERIALIZER_METHOD+"("+DESERIALIZATION_BUFFER+"& buf);"); h.newline(); h.forceNewline(); printTemplateSignature(ct.x10Def().typeParameters(), sw); sw.write(make_ref("x10::lang::Reference")+" "+klass+"::"+DESERIALIZER_METHOD+"("+DESERIALIZATION_BUFFER+"& buf) {"); sw.newline(4); sw.begin(0); sw.writeln(make_ref(klass)+" this_ = "+ "new (memset(x10aux::alloc"+chevrons(klass)+"(), 0, sizeof("+klass+"))) "+klass+"();"); sw.writeln("buf.record_reference(this_);"); sw.writeln("this_->"+DESERIALIZE_BODY_METHOD+"(buf);"); sw.write("return this_;"); sw.end(); sw.newline(); sw.writeln("}"); sw.forceNewline(); } // _deserialize_body() h.write("public: "); h.write("void "+DESERIALIZE_BODY_METHOD+"("+DESERIALIZATION_BUFFER+"& buf);"); h.newline(0); printTemplateSignature(ct.x10Def().typeParameters(), w); w.write("void "+klass+"::"+DESERIALIZE_BODY_METHOD+"("+DESERIALIZATION_BUFFER+"& buf) {"); w.newline(4); w.begin(0); if (customSerialization) { w.writeln("/* NOTE: Implements x10.io.CustomSerialization */"); w.writeln(translateType(ts.SerialData(), true)+ "val_ = buf.read"+chevrons(translateType(ts.SerialData(), true))+"();"); w.writeln(CONSTRUCTOR+"(val_);"); } else { if (parent != null && parent.isClass()) { w.write(translateType(parent)+"::"+DESERIALIZE_BODY_METHOD+"(buf);"); w.newline(); } for (int i = 0; i < type.fields().size(); i++) { if (i != 0) w.newline(); FieldInstance f = (FieldInstance) type.fields().get(i); if (f instanceof X10FieldInstance && !query.ifdef(((X10FieldInstance) f).x10Def())) continue; if (f.flags().isStatic() || query.isSyntheticField(f.name().toString())) continue; if (f.flags().isTransient()) // don't serialize transient fields of classes continue; String fieldName = mangled_field_name(f.name().toString()); w.write(fieldName+" = buf.read"+chevrons(translateType(f.type(),true))+"();"); } } w.end(); w.newline(); w.write("}"); w.newline(); w.forceNewline(); } void generateStructSerializationMethods(ClassType type, StreamWrapper sw) { X10ClassType ct = (X10ClassType) type.toClass(); TypeSystem ts = (TypeSystem) type.typeSystem(); X10CPPContext_c context = (X10CPPContext_c) tr.context(); ClassifiedStream w = sw.body(); ClassifiedStream h = sw.header(); String klass = translateType(type); h.forceNewline(); // _serialize() h.write("static void "+SERIALIZE_METHOD+"("+klass+" this_, "+SERIALIZATION_BUFFER+"& buf);"); h.newline(0); h.forceNewline(); printTemplateSignature(ct.x10Def().typeParameters(), w); w.write("void "+klass+"::"+SERIALIZE_METHOD+"("+klass+" this_, "+SERIALIZATION_BUFFER+"& buf) {"); w.newline(4); w.begin(0); Type parent = type.superClass(); if (parent != null) { w.write(translateType(parent)+"::"+SERIALIZE_METHOD+"(this_, buf);"); w.newline(); } for (int i = 0; i < type.fields().size(); i++) { if (i != 0) w.newline(); FieldInstance f = (FieldInstance) type.fields().get(i); if (f.flags().isStatic() || query.isSyntheticField(f.name().toString())) continue; if (f.flags().isTransient()) // don't serialize transient fields continue; String fieldName = mangled_field_name(f.name().toString()); w.write("buf.write(this_->"+fieldName+");"); w.newline(); } w.end(); w.newline(); w.write("}"); w.newline(); w.forceNewline(); // _deserialize() h.write("static "+klass+" "+DESERIALIZE_METHOD+"("+DESERIALIZATION_BUFFER+"& buf) {"); h.newline(4) ; h.begin(0); h.writeln(klass+" this_;"); h.writeln("this_->"+DESERIALIZE_BODY_METHOD+"(buf);"); h.write("return this_;"); h.end(); h.newline(); h.write("}"); h.newline(); h.forceNewline(); // _deserialize_body() h.write("void "+DESERIALIZE_BODY_METHOD+"("+DESERIALIZATION_BUFFER+"& buf);"); h.newline(0); printTemplateSignature(ct.x10Def().typeParameters(), w); w.write("void "+klass+"::"+DESERIALIZE_BODY_METHOD+"("+DESERIALIZATION_BUFFER+"& buf) {"); w.newline(4); w.begin(0); if (parent != null) { w.write(translateType(parent)+"::"+DESERIALIZE_BODY_METHOD+"(buf);"); w.newline(); } for (int i = 0; i < type.fields().size(); i++) { if (i != 0) w.newline(); FieldInstance f = (FieldInstance) type.fields().get(i); if (f.flags().isStatic() || query.isSyntheticField(f.name().toString())) continue; if (f.flags().isTransient()) // don't serialize transient fields continue; String fieldName = mangled_field_name(f.name().toString()); w.write(fieldName+" = buf.read"+chevrons(translateType(f.type(),true))+"();"); } w.end(); w.newline(); w.write("}"); w.newline(); w.forceNewline(); } public void emitUniqueNS(QName name, ArrayList<String> history, CodeWriter w) { if (name == null) return; if (!history.contains(name.toString())) { openNamespaces(w, name); closeNamespaces(w, name); w.newline(); w.write("using namespace "+translateFQN(name.toString())+";"); history.add(name.toString()); } return; } public static void openNamespaces(CodeWriter h, QName name) { if (name == null) return; openNamespaces(h, name.qualifier()); h.write("namespace "+mangle_to_cpp(name.name().toString())+" { "); } public static void closeNamespaces(CodeWriter h, QName name) { if (name == null) return; h.write("} "); closeNamespaces(h, name.qualifier()); } public String makeUnsignedType(Type t) { // FIXME: HACK! if (t.isInt()) return "uint32_t"; if (t.isLong()) return "uint64_t"; return "unsigned "+translateType(t); } public static void dumpString(String str, CodeWriter w) { int pos = 0; int nl = 0; while ((nl = str.indexOf('\n', pos)) != -1) { w.write(str.substring(pos, nl)); w.newline(0); pos = nl+1; } w.write(str.substring(pos)); } // Either #SOME_VAR123 // or ##SOME_VAR123#default value if var that key is not known# // the second variation is only useful for properties private static final Pattern nativeSubstRegex = Pattern.compile("#(#(([0-9A-Za-z_]+)#([^#]*)#)|([0-9A-Za-z_]+))"); private static String nativeSubst(String annotation, Map<String,Object> components, String pattern) { Matcher m = nativeSubstRegex.matcher(pattern); int last=0; StringBuffer out = new StringBuffer(); while (m.find()) { out.append(pattern.substring(last,m.start())); last = m.end(); String key = m.group(5); String default_ = null; if (key==null) { // ## form key = m.group(3); default_ = m.group(4); } Object val = components.get(key); if (val==null) val = default_; if (val==null) { throw new InternalCompilerError(annotation+" \""+pattern+"\" cannot find substitution for #"+key); } if (val instanceof Type) { out.append(translateType((Type)val, true)); } else { out.append(val); } } out.append(pattern.substring(last)); return out.toString(); } public void nativeSubst(String annotation, Map<String, Object> components, Translator tr, String pattern, CodeWriter w) { Matcher m = nativeSubstRegex.matcher(pattern); int last=0; while (m.find()) { w.write(pattern.substring(last,m.start())); last = m.end(); String key = m.group(5); String default_ = null; if (key==null) { // ## form key = m.group(3); default_ = m.group(4); } Object val = components.get(key); if (val==null) val = default_; if (val==null) { throw new InternalCompilerError(annotation+" \""+pattern+"\" cannot find substitution for #"+key); } if (val instanceof Node) { Node n = (Node) val; tr.print(null, n, w); } else if (val instanceof Type) { w.write(translateType((Type)val, true)); } else if (val != null) { w.write(val.toString()); } } w.write(pattern.substring(last)); } } // vim:tabstop=4:shiftwidth=4:expandtab