/* * 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.assertNumberOfInitializers; import static x10cpp.visit.ASTQuery.getConstructorId; import static x10cpp.visit.ASTQuery.getCppRep; import static x10cpp.visit.ASTQuery.getStringPropertyInit; import static x10cpp.visit.Emitter.mangled_field_name; import static x10cpp.visit.Emitter.mangled_method_name; import static x10cpp.visit.Emitter.mangled_non_method_name; import static x10cpp.visit.Emitter.translateFQN; import static x10cpp.visit.Emitter.translate_mangled_FQN; import static x10cpp.visit.Emitter.voidTemplateInstantiation; import static x10cpp.visit.SharedVarsMethods.CONSTRUCTOR; import static x10cpp.visit.SharedVarsMethods.DESERIALIZATION_BUFFER; import static x10cpp.visit.SharedVarsMethods.DESERIALIZE_METHOD; import static x10cpp.visit.SharedVarsMethods.MAKE; import static x10cpp.visit.SharedVarsMethods.CPP_NATIVE_STRING; 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.STRUCT_EQUALS; import static x10cpp.visit.SharedVarsMethods.STRUCT_EQUALS_METHOD; import static x10cpp.visit.SharedVarsMethods.STRUCT_THIS; import static x10cpp.visit.SharedVarsMethods.THIS; import static x10cpp.visit.SharedVarsMethods.VOID; import static x10cpp.visit.SharedVarsMethods.VOID_PTR; import static x10cpp.visit.SharedVarsMethods.REFERENCE_TYPE; import static x10cpp.visit.SharedVarsMethods.CLOSURE_TYPE; import static x10cpp.visit.SharedVarsMethods.CLASS_TYPE; import static x10cpp.visit.SharedVarsMethods.chevrons; import static x10cpp.visit.SharedVarsMethods.getId; import static x10cpp.visit.SharedVarsMethods.getUniqueId_; import static x10cpp.visit.SharedVarsMethods.make_ref; import static x10cpp.visit.SharedVarsMethods.make_captured_lval; import static x10cpp.visit.SharedVarsMethods.refsAsPointers; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Map; import polyglot.ast.Allocation_c; import polyglot.ast.AmbReceiver; import polyglot.ast.ArrayAccess_c; import polyglot.ast.ArrayInit_c; import polyglot.ast.Assert_c; import polyglot.ast.Assign_c; import polyglot.ast.Binary; import polyglot.ast.Binary_c; import polyglot.ast.Block; import polyglot.ast.Block_c; import polyglot.ast.BooleanLit_c; import polyglot.ast.Branch_c; import polyglot.ast.CanonicalTypeNode; import polyglot.ast.Case_c; import polyglot.ast.Catch; import polyglot.ast.Catch_c; import polyglot.ast.CharLit_c; import polyglot.ast.ClassBody_c; import polyglot.ast.ClassMember; import polyglot.ast.Conditional_c; import polyglot.ast.ConstructorCall; import polyglot.ast.ConstructorCall_c; import polyglot.ast.ConstructorDecl_c; import polyglot.ast.Do_c; import polyglot.ast.Empty_c; import polyglot.ast.Eval_c; import polyglot.ast.Expr; import polyglot.ast.FieldAssign; import polyglot.ast.FieldAssign_c; import polyglot.ast.FieldDecl_c; import polyglot.ast.Field_c; import polyglot.ast.FloatLit_c; import polyglot.ast.ForInit; import polyglot.ast.ForUpdate; import polyglot.ast.For_c; import polyglot.ast.Formal; import polyglot.ast.Formal_c; import polyglot.ast.Id_c; import polyglot.ast.If_c; import polyglot.ast.Import_c; import polyglot.ast.Initializer_c; import polyglot.ast.IntLit; import polyglot.ast.IntLit_c; import polyglot.ast.Labeled_c; import polyglot.ast.Lit; import polyglot.ast.LocalClassDecl_c; import polyglot.ast.LocalDecl_c; import polyglot.ast.Local_c; import polyglot.ast.MethodDecl; import polyglot.ast.MethodDecl_c; import polyglot.ast.New_c; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.Node_c; import polyglot.ast.NullLit_c; import polyglot.ast.PackageNode_c; import polyglot.ast.Receiver; import polyglot.ast.Return_c; import polyglot.ast.Stmt; import polyglot.ast.StringLit_c; import polyglot.ast.SwitchBlock_c; import polyglot.ast.SwitchElement; import polyglot.ast.Switch_c; import polyglot.ast.Throw_c; import polyglot.ast.Try; import polyglot.ast.Try_c; import polyglot.ast.TypeNode; import polyglot.ast.Unary; import polyglot.ast.Unary_c; import polyglot.ast.While_c; import polyglot.main.Reporter; import polyglot.types.ClassType; import polyglot.types.CodeInstance; import polyglot.types.ConstructorInstance; import polyglot.types.Context; import polyglot.types.FieldInstance; import polyglot.types.Flags; import polyglot.types.FunctionDef; import polyglot.types.InitializerInstance; import polyglot.types.LocalDef; import polyglot.types.LocalInstance; import polyglot.types.MethodDef; import polyglot.types.Name; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; 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.Pair; import polyglot.util.Position; import polyglot.util.StringUtil; import polyglot.util.TypedList; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import polyglot.visit.Translator; import x10.Configuration; import x10.ast.AssignPropertyCall_c; import x10.ast.Async_c; import x10.ast.AtEach_c; import x10.ast.AtExpr_c; import x10.ast.AtStmt_c; import x10.ast.Atomic_c; import x10.ast.Closure; import x10.ast.ClosureCall; import x10.ast.ClosureCall_c; import x10.ast.Closure_c; import x10.ast.Finish_c; import x10.ast.ForLoop_c; import x10.ast.HasZeroTest_c; import x10.ast.Here_c; import x10.ast.LocalTypeDef_c; import x10.ast.Next_c; import x10.ast.ParExpr_c; import x10.ast.PropertyDecl; import x10.ast.PropertyDecl_c; import x10.ast.SettableAssign; import x10.ast.SettableAssign_c; import x10.ast.StmtExpr_c; import x10.ast.StmtSeq_c; import x10.ast.SubtypeTest_c; import x10.ast.Tuple_c; import x10.ast.TypeDecl_c; import x10.ast.When_c; import x10.ast.X10Binary_c; import x10.ast.X10Call_c; import x10.ast.X10CanonicalTypeNode; import x10.ast.X10CanonicalTypeNode_c; import x10.ast.X10Cast_c; import x10.ast.X10ClassDecl_c; import x10.ast.X10Field_c; import x10.ast.X10Formal; import x10.ast.X10Instanceof_c; import x10.ast.X10Local_c; import x10.ast.X10MethodDecl; import x10.ast.X10MethodDecl_c; import x10.ast.X10Special_c; import x10.ast.X10Unary_c; import x10.errors.Warnings; import x10.extension.X10Ext; import x10.extension.X10Ext_c; import x10.types.ClosureDef; import x10.types.ClosureInstance; import x10.types.ParameterType; import x10.types.FunctionType; import x10.types.ThisDef; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10ConstructorInstance; import x10.types.X10Def; import x10.types.X10FieldDef; import x10.types.X10FieldInstance; import x10.types.X10LocalDef; import x10.types.X10MethodDef; import x10.types.MethodInstance; import x10.types.X10ParsedClassType_c; import polyglot.types.TypeSystem_c.BaseTypeEquals; import x10.types.checker.Converter; import x10.visit.StaticNestedClassRemover; import x10.visit.X10DelegatingVisitor; import x10.util.ClassifiedStream; import x10.util.ClosureSynthesizer; import x10.util.StreamWrapper; import x10cpp.X10CPPCompilerOptions; import x10cpp.X10CPPJobExt; import x10cpp.debug.LineNumberMap; import x10cpp.types.X10CPPContext_c; /** * Primary visitor for the C++ codegenerator. */ public class MessagePassingCodeGenerator extends X10DelegatingVisitor { protected final StreamWrapper sw; protected final Translator tr; protected Emitter emitter; protected ASTQuery query; protected Reporter reporter; public MessagePassingCodeGenerator(StreamWrapper sw, Translator tr) { this.sw = sw; this.tr = tr; this.emitter = new Emitter(tr); this.query = new ASTQuery(tr); this.reporter = tr.job().extensionInfo().getOptions().reporter; } public void visit(Node n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); tr.job().compiler().errorQueue().enqueue(ErrorInfo.SEMANTIC_ERROR, "Unhandled node type: "+n.getClass(), n.position()); //n.translate(w, tr); } public void visit(Allocation_c n) { Type type = n.type(); sw.allowBreak(0, " "); String typeName = Emitter.translateType(type); X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (null != context.getStackAllocName()) return; if (Types.isX10Struct(type)) { sw.write(typeName+ "::" +SharedVarsMethods.ALLOC+ "()"); } else { // XTENLANG-1407: Remove this memset call once we finish the default value specification/implementation. // Expect it to be more efficient to explicitly initialize all of the object fields instead // of first calling memset, then storing into most of the fields a second time. sw.write("((new (memset(x10aux::alloc"+chevrons(typeName)+"(), 0, sizeof("+typeName+"))) "+typeName+"()))"); sw.newline(); } } public void visit(ConstructorCall_c call) { String targetClass = Emitter.translateType(call.constructorInstance().container()); Expr target = call.target(); sw.write("("); if (target == null) { sw.write("this"); } else { call.print(target, sw, tr); } sw.write(")->::" +targetClass+ "::" +SharedVarsMethods.CONSTRUCTOR+ "("); boolean noArgsYet = true; List<Expr> args = call.arguments(); for (int i=0; i<args.size(); i++) { if (noArgsYet) { sw.allowBreak(2, 2, "", 0); // miser mode sw.begin(0); noArgsYet = false; } else { sw.write(","); sw.allowBreak(0, " "); } Expr e = args.get(i); call.print(e, sw, tr); } if (!noArgsYet) sw.end(); sw.write(");"); sw.newline(); } public void visit(TypeDecl_c n) { // do nothing sw.write(" /* " + n + " *" + "/ "); sw.newline(); } public void visit(LocalTypeDef_c n) { // do nothing sw.write(" /* " + n + " *" + "/ "); sw.newline(); } public void visit(X10ClassDecl_c n) { processClass(n); } /** * Returns an all-void instantiation of a given class type ct. */ public static X10ClassType getStaticMemberContainer(X10ClassDef cd) { if (cd.typeParameters().size() == 0) return cd.asType(); TypeSystem xts = cd.typeSystem(); List<Type> args = new TypedList<Type>(new ArrayList<Type>(), Type.class, false); for (int i = 0; i < cd.typeParameters().size(); i++) { args.add(xts.Void()); } return cd.asType().typeArguments(args); } private void extractGenericStaticDecls(X10ClassDef cd, ClassifiedStream h) { if (cd.typeParameters().size() == 0) return; X10CPPContext_c context = (X10CPPContext_c) tr.context(); h.write("template <> class "); h.write(mangled_non_method_name(cd.name().toString())); h.write(voidTemplateInstantiation(cd.typeParameters().size())); if (!cd.isStruct()) { Ref<? extends Type> st = cd.superType(); h.write(" : public "); if (st == null ) { h.write("x10::lang::X10Class"); } else { X10ClassDef sdef = ((X10ClassType) Types.baseType(st.get())).x10Def(); h.write(Emitter.translateType(getStaticMemberContainer(sdef), false)); } } h.allowBreak(0, " "); h.write("{"); h.newline(4); h.begin(0); h.write("public:"); h.newline(); h.write("static x10aux::RuntimeType rtt;"); h.newline(); h.write("static const x10aux::RuntimeType* getRTT() { return & rtt; }"); h.newline(); // Process all static fields and methods for (ClassMember dec : context.pendingStaticDecls()) { if (dec instanceof FieldDecl_c) { FieldDecl_c fd = (FieldDecl_c) dec; ((X10CPPTranslator)tr).setContext(fd.enterScope(context)); // FIXME sw.pushCurrentStream(h); emitter.printHeader(fd, h, tr, false); h.write(";"); sw.popCurrentStream(); ((X10CPPTranslator)tr).setContext(context); // FIXME } else if (dec instanceof X10MethodDecl_c) { X10MethodDecl_c md = (X10MethodDecl_c) dec; ((X10CPPTranslator)tr).setContext(md.enterScope(context)); // FIXME sw.pushCurrentStream(h); emitter.printHeader(md, sw, tr, false, false); sw.popCurrentStream(); h.write(";"); ((X10CPPTranslator)tr).setContext(context); // FIXME } h.newline(); h.forceNewline(); } extractGenericStaticInits(cd); h.end(); h.newline(); h.write("};"); h.newline(); } private void extractGenericStaticInits(X10ClassDef cd) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); // Always write non-template static decls into the implementation file ClassifiedStream save_w = sw.currentStream(); ClassifiedStream w = context.staticDefinitions; sw.pushCurrentStream(w); X10ClassType declClass = (X10ClassType)cd.asType().toClass(); String declClassName = translate_mangled_FQN(cd.fullName().toString()); String container = declClassName+voidTemplateInstantiation(cd.typeParameters().size()); sw.write("x10aux::RuntimeType "+container+"::rtt;"); sw.newline(); for (ClassMember dec : context.pendingStaticDecls()) { if (dec instanceof FieldDecl_c) { FieldDecl_c fd = (FieldDecl_c) dec; ((X10CPPTranslator)tr).setContext(fd.enterScope(context)); // FIXME generateStaticFieldSupportCode(fd, container, sw); ((X10CPPTranslator)tr).setContext(context); // FIXME } else if (dec instanceof X10MethodDecl_c) { X10MethodDecl_c md = (X10MethodDecl_c) dec; X10MethodDef def = md.methodDef(); boolean templateMethod = def.typeParameters().size() != 0; if (templateMethod) sw.pushCurrentStream(save_w); ((X10CPPTranslator)tr).setContext(md.enterScope(context)); // FIXME emitter.printTemplateSignature(def.typeParameters(), sw); emitter.printType(md.returnType().type(), sw); sw.allowBreak(2, " "); sw.write(container+"::"); sw.write(mangled_method_name(md.name().id().toString()) + "("); sw.begin(0); boolean first = true; for (Formal f : md.formals()) { if (first) { first = false; } else { sw.write(","); sw.allowBreak(0, " "); } md.print(f, sw, tr); } sw.end(); sw.write(")"); if (md.body() != null) { sw.allowBreak(0, " "); md.printBlock(md.body(), sw, tr); } sw.newline(); ((X10CPPTranslator)tr).setContext(context); // FIXME if (templateMethod) sw.popCurrentStream(); } else if (dec instanceof Initializer_c) { assert (false) : ("Static initializer alert!"); } else if (dec instanceof X10ClassDecl_c) { assert (false) : ("Nested class alert!"); } } sw.forceNewline(); sw.popCurrentStream(); } private void extractAllClassTypes(Type t, List<ClassType> types, Set<ClassType> dupes) { TypeSystem xts = (TypeSystem) t.typeSystem(); t = xts.expandMacros(t); if (!t.isClass()) return; if (t instanceof X10ClassType && ((X10ClassType)t).isJavaType()) { // ignore Java types. If they are actually needed in the generated code, // it is a programming error that we will "report" via a post-compilation error. return; } X10ClassType ct = (X10ClassType) t.toClass(); if (!dupes.contains(ct)) { dupes.add(ct); types.add(ct); } if (ct.typeArguments() != null) { for (Type pt : ct.typeArguments()) extractAllClassTypes(pt, types, dupes); } if (ct.isMember() || ct.isLocal()) extractAllClassTypes(ct.container(), types, dupes); } private void declareClass(X10ClassDef cd, ClassifiedStream h) { assert (cd != null); QName pkg = null; if (cd.package_() != null) pkg = cd.package_().get().fullName(); if (pkg != null) { Emitter.openNamespaces(h, pkg); h.newline(0); } emitter.printTemplateSignature(cd.typeParameters(), h); String name; if (cd.isFunction()) { name = Emitter.baseName((FunctionType)cd.asType(), false); } else { name = StaticNestedClassRemover.mangleName(cd).toString(); } h.write("class "+Emitter.mangled_non_method_name(name)+";"); h.newline(); if (pkg != null) { h.newline(0); Emitter.closeNamespaces(h, pkg); h.newline(0); } } public static String getHeader(ClassType ct) { String pkg = null; if (ct.package_() != null) pkg = ct.package_().fullName().toString(); if (ct instanceof FunctionType) { String name = Emitter.baseName((FunctionType)ct, false); return X10CPPTranslator.outputFileName(pkg, name, StreamWrapper.Header); } else { Name name = StaticNestedClassRemover.mangleName(ct.def()); String header = X10CPPTranslator.outputFileName(pkg, name.toString(), StreamWrapper.Header); return header; } } private static String getHeaderGuard(String header) { return header.replace('/','_').replace('.','_').replace('$','_').toUpperCase(); } void processClass(X10ClassDecl_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); X10ClassDef def = (X10ClassDef) n.classDef(); TypeSystem xts = tr.typeSystem(); boolean isStruct = xts.isStructType(def.asType()); X10Ext ext = (X10Ext) n.ext(); if (getCppRep(def) != null) { // emit no c++ code as this is a native rep class return; } assert (!def.isNested()) : ("Nested class alert!"); boolean inTemplate = def.typeParameters().size() != 0; ClassifiedStream save_body = sw.body(); ClassifiedStream save_header = sw.header(); ClassifiedStream save_generic = context.genericFunctions; ClassifiedStream save_generic_cls = context.genericFunctionClosures; ClassifiedStream save_closures = context.closures; ClassifiedStream save_static_defs = context.staticDefinitions; ClassifiedStream save_static_closure_defs = context.staticClosureDefinitions; // Header stream ClassifiedStream h = sw.getNewStream(StreamWrapper.Header, false); // Stream for closures that are within generic functions (always in the header, may be empty) ClassifiedStream g_cls = sw.getNewStream(StreamWrapper.Header, false); context.genericFunctionClosures = g_cls; // Stream for generic functions (always in the header, may be empty) ClassifiedStream g = sw.getNewStream(StreamWrapper.Header, false); context.genericFunctions = g; // Implementation stream. // In generic context, in .h, but after the logical header stream. // In non-generic context, in .cc ClassifiedStream w_header = sw.getNewStream(inTemplate ? StreamWrapper.Header : StreamWrapper.CC, false); ClassifiedStream w_closures = sw.getNewStream(inTemplate ? StreamWrapper.Header : StreamWrapper.CC, false); context.closures = w_closures; ClassifiedStream w_body = sw.getNewStream(inTemplate ? StreamWrapper.Header : StreamWrapper.CC, false); ClassifiedStream stat_defs = sw.getNewStream(StreamWrapper.CC, false); context.staticDefinitions = stat_defs; ClassifiedStream stat_cls_defs = sw.getNewStream(StreamWrapper.CC, false); context.staticClosureDefinitions = stat_cls_defs; ClassifiedStream w_footer = sw.getNewStream(inTemplate ? StreamWrapper.Header : StreamWrapper.CC, false); // Dependences guard closing stream (comes at the end of the header) ClassifiedStream z = sw.getNewStream(StreamWrapper.Header, false); sw.set(h, w_body); context.setInsideClosure(false); // Write the header for the class String cheader = getHeader(def.asType()); String cguard = getHeaderGuard(cheader); h.write("#ifndef __"+cguard); h.newline(); h.write("#define __"+cguard); h.newline(); h.forceNewline(0); h.write("#include <x10rt.h>"); h.newline(); h.forceNewline(0); // process annotations relating to additional h/c++ files try { X10CPPCompilerOptions opts = (X10CPPCompilerOptions) tr.job().extensionInfo().getOptions(); List<X10ClassType> as = ext.annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.NativeCPPInclude"))); for (Type at : as) { ASTQuery.assertNumberOfInitializers(at, 1); String include = getStringPropertyInit(at, 0); h.write("#include \""+include+"\""); h.newline(); } } catch (SemanticException e) { assert false : e; } h.forceNewline(0); g.write("#ifndef "+cguard+"_GENERICS"); g.newline(); g.write("#define "+cguard+"_GENERICS"); g.newline(); if (inTemplate) { w_header.write("#ifndef "+cguard+"_IMPLEMENTATION"); w_header.newline(); w_header.write("#define "+cguard+"_IMPLEMENTATION"); w_header.newline(); } w_header.write("#include <"+cheader+">"); w_header.newline(); w_header.forceNewline(0); if (inTemplate) { stat_defs.writeln("#include <"+cheader+">"); stat_defs.forceNewline(0); } String packageName = context.package_() == null ? null : context.package_().fullName().toString(); Set<String> allIncludes = CollectionFactory.newHashSet(); if (n.superClass() != null) { ClassType ct = n.superClass().type().toClass(); X10ClassDef scd = (X10ClassDef) ct.def(); if (scd != def) { String header = getHeader(ct); String guard = getHeaderGuard(header); h.write("#define "+guard+"_NODEPS"); h.newline(); h.write("#include <" + header + ">"); h.newline(); h.write("#undef "+guard+"_NODEPS"); h.newline(); allIncludes.add(getHeader(ct)); } ArrayList<ClassType> types = new ArrayList<ClassType>(); Set<ClassType> dupes = CollectionFactory.newHashSet(); dupes.add(ct); extractAllClassTypes(ct, types, dupes); for (ClassType t : types) { X10ClassDef cd = ((X10ClassType)t).x10Def(); if (cd != def && getCppRep(cd) == null) { String header = getHeader(t); if (!allIncludes.contains(header)) { declareClass(cd, h); allIncludes.add(header); } } } } for (TypeNode i : n.interfaces()) { ClassType ct = i.type().toClass(); X10ClassDef icd = (X10ClassDef) ct.def(); if (icd != def) { String header = getHeader(ct); String guard = getHeaderGuard(header); h.writeln("#define "+guard+"_NODEPS"); h.writeln("#include <" + header + ">"); h.writeln("#undef "+guard+"_NODEPS"); allIncludes.add(getHeader(ct)); } ArrayList<ClassType> types = new ArrayList<ClassType>(); Set<ClassType> dupes = CollectionFactory.newHashSet(); dupes.add(ct); extractAllClassTypes(ct, types, dupes); for (ClassType t : types) { X10ClassDef cd = ((X10ClassType)t).x10Def(); if (cd != def && getCppRep(cd) == null) { String header = getHeader(t); if (!allIncludes.contains(header)) { declareClass(cd, h); allIncludes.add(header); } } } } // If any instance fields are struct types, then include the .h List<FieldInstance> fields = def.asType().fields(); if (!fields.isEmpty()) { Set<Type> dupes = CollectionFactory.newHashSet(); Set<ClassType> dupes2 = CollectionFactory.newHashSet(); Set<ClassType> dupes3 = CollectionFactory.newHashSet(); for (FieldInstance fi : fields) { Type fct = fi.type(); if (!fi.flags().isStatic()) { if (!((X10FieldInstance) fi).annotationsMatching(xts.Embed()).isEmpty()) { ArrayList<ClassType> types = new ArrayList<ClassType>(); extractAllClassTypes(fct, types, dupes2); for (ClassType t : types) { X10ClassDef cd = ((X10ClassType)t).x10Def(); if (cd != def && getCppRep(cd) == null) { String header = getHeader(t); String guard = getHeaderGuard(header); h.writeln("#define "+guard+"_NODEPS"); h.writeln("#include <" + header + ">"); h.writeln("#undef "+guard+"_NODEPS"); allIncludes.add(getHeader(t)); } } } if (!dupes.contains(fct)) { dupes.add(fct); ArrayList<ClassType> types = new ArrayList<ClassType>(); extractAllClassTypes(fct, types, dupes3); if (xts.isStruct(fct)) { types.add((X10ClassType) Types.baseType(fct)); } for (ClassType t : types) { if (xts.isStructType(t)) { String header = getHeader(t.toClass()); String guard = getHeaderGuard(header); h.writeln("#define "+guard+"_NODEPS"); h.writeln("#include <" + header + ">"); h.writeln("#undef "+guard+"_NODEPS"); allIncludes.add(getHeader(t)); } } } } } } ArrayList<ClassType> types = referencedTypes(n, def); for (ClassType ct : types) { X10ClassDef cd = (X10ClassDef) ct.def(); if (cd == def) continue; if (cd.isAnonymous()) continue; String header = getHeader(ct); if (!allIncludes.contains(header)) { declareClass(cd, h); allIncludes.add(header); } } if (def.package_() != null) { QName pkgName = def.package_().get().fullName(); Emitter.openNamespaces(h, pkgName); h.newline(0); h.forceNewline(0); if (def.fullName().toString().equals("x10.lang.Place")) { h.write("class Any; class String; // Forward reference are required in Place to prevent circularity"); h.newline(); } } /* * Ideally, classProperties would be added to the child context * that will be created for processing the classBody, but there * is no way to do that. So instead we add and remove the properties * in the global context, for each class. */ context.resetStateForClass(n.properties()); if (inTemplate && !def.isStruct()) { // Pre-declare the void specialization for statics emitter.printTemplateSignature(def.typeParameters(), h); h.write("class "); h.write(mangled_non_method_name(def.name().toString())); h.write(";"); h.newline(); h.write("template <> class "); h.write(mangled_non_method_name(def.name().toString())); h.write(voidTemplateInstantiation(def.typeParameters().size())); h.write(";"); h.newline(); } // Open class/namespace bodies emitter.printHeader(n, h, tr); h.allowBreak(0, " "); h.write(" {"); h.newline(4); h.begin(0); n.print(n.body(), sw, tr); // Close class bodies h.end(); h.newline(0); h.writeln("};"); h.forceNewline(0); emitter.printRTTDefn((X10ClassType) Types.baseType(def.asType()), sw); ((X10CPPTranslator)tr).setContext(n.enterChildScope(n.body(), context)); // FIXME extractGenericStaticDecls(def, h); /* * See comment about resetStateForClass() above. */ context.clearStateForClass(); ((X10CPPTranslator)tr).setContext(context); // FIXME // Write the footer for the class if (def.package_() != null) { QName pkgName = def.package_().get().fullName(); h.newline(0); h.forceNewline(0); Emitter.closeNamespaces(h, pkgName); h.newline(0); } h.write("#endif // " + cguard); h.newline(0); h.forceNewline(0); g.write("#endif // "+cguard+"_GENERICS"); g.newline(); if (inTemplate) { w_footer.write("#endif // "+cguard+"_IMPLEMENTATION"); w_footer.newline(); } // The declarations below are intentionally outside of the guard if (context.package_() != null) { QName qn = context.package_().fullName(); Emitter.openNamespaces(h, qn); h.newline(0); } emitter.printTemplateSignature(def.typeParameters(), h); h.write("class "+Emitter.mangled_non_method_name(n.name().toString())+";"); h.newline(0); if (context.package_() != null) { h.newline(0); QName qn = context.package_().fullName(); Emitter.closeNamespaces(h, qn); h.newline(0); } h.forceNewline(0); // [IP] Ok to include here, since the class is already defined h.write("#ifndef "+cguard+"_NODEPS"); h.newline(); h.write("#define "+cguard+"_NODEPS"); h.newline(); boolean implInHeader = n.typeParameters().size() > 0; if (!implInHeader) { Type headerAnnotation = null; try { headerAnnotation = xts.systemResolver().findOne(HEADER_ANNOTATION); } catch (SemanticException e) { // ignore. } for (ClassMember m : n.body().members()) { if (headerAnnotation != null && !((X10Ext) m.ext()).annotationMatching(headerAnnotation).isEmpty()) { implInHeader = true; // conservative; something has been forced to the header stream. break; } if (m instanceof FieldDecl_c) { FieldDecl_c fd = (FieldDecl_c) m; if (fd.flags().flags().isStatic() && !fd.type().type().isNumeric()) { implInHeader = true; // conservative; we may have generated an inline get method into the generic functions stream break; } } else if (m instanceof X10MethodDecl_c) { X10MethodDecl_c md = (X10MethodDecl_c) m; if (md.typeParameters().size() > 0) { implInHeader = true; // generic function went in header stream break; } } } } ClassifiedStream incS = implInHeader ? h : w_header; for (String header : allIncludes) { incS.writeln("#include <" + header + ">"); } z.write("#endif // __"+cguard+"_NODEPS"); h.newline(); z.forceNewline(0); context.genericFunctions = save_generic; context.genericFunctionClosures = save_generic_cls; context.closures = save_closures; context.staticDefinitions = save_static_defs; context.staticClosureDefinitions = save_static_closure_defs; sw.set(save_header, save_body); } /** * This method walks the AST for the ClassDecl n and finds all AST nodes * that refer to types. For example allocations, type nodes, instance field * access and method calls. It then extracts all the types referenced in these * AST nodes by calling the helper method extractAllClassTypes. */ private ArrayList<ClassType> referencedTypes(X10ClassDecl_c n, X10ClassDef def) { X10SearchVisitor<Node> xTypes = new X10SearchVisitor<Node>(X10CanonicalTypeNode_c.class, Closure_c.class, Tuple_c.class, Allocation_c.class, X10Call_c.class, Field_c.class, FieldAssign_c.class); n.visit(xTypes); ArrayList<ClassType> types = new ArrayList<ClassType>(); Set<ClassType> dupes = CollectionFactory.newHashSet(); dupes.add(def.asType()); if (xTypes.found()) { ArrayList<Node> typeNodesAndClosures = xTypes.getMatches(); for (Node tn : typeNodesAndClosures) { if (tn instanceof X10CanonicalTypeNode_c) { X10CanonicalTypeNode_c t = (X10CanonicalTypeNode_c) tn; Type tt = t.type(); if (tt.isClass() && tt.toClass().isAnonymous()) { ClassType c = tt.toClass(); assert (c.interfaces().size() == 1); tt = c.interfaces().get(0); } extractAllClassTypes(tt, types, dupes); } else if (tn instanceof Closure_c) { Closure_c t = (Closure_c) tn; ClassType c = t.type().toClass(); assert (c.interfaces().size() == 1); extractAllClassTypes(c.interfaces().get(0), types, dupes); } else if (tn instanceof Tuple_c) { extractAllClassTypes(((Tuple_c) tn).type(), types, dupes); } else if (tn instanceof Allocation_c) { extractAllClassTypes(((Allocation_c) tn).type(), types, dupes); } else if (tn instanceof X10Call_c) { extractAllClassTypes(((X10Call_c) tn).methodInstance().container(), types, dupes); extractAllClassTypes(((X10Call_c) tn).methodInstance().returnType(), types, dupes); } else if (tn instanceof Field_c) { Field_c f = (Field_c)tn; if (!f.flags().isStatic()) { extractAllClassTypes(f.fieldInstance().container(), types, dupes); } } else if (tn instanceof FieldAssign_c) { FieldAssign_c f = (FieldAssign_c) tn; if (!f.fieldInstance().flags().isStatic()) { extractAllClassTypes(f.fieldInstance().container(), types, dupes); } } } } return types; } public void visit(LocalClassDecl_c n) { assert (false) : ("Local classes should have been removed by a separate pass"); } public void visit(ClassBody_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); X10ClassType currentClass = (X10ClassType) context.currentClass(); X10ClassType superClass = (X10ClassType) Types.baseType(currentClass.superClass()); TypeSystem xts = (TypeSystem) tr.typeSystem(); if (currentClass.flags().isInterface()) { visitInterfaceBody(n, context, currentClass, superClass, xts); } else if (currentClass.isX10Struct()) { visitStructBody(n, context, currentClass, superClass, xts); } else { visitClassBody(n, context, currentClass, superClass, xts); } } private void visitInterfaceBody(ClassBody_c n, X10CPPContext_c context, X10ClassType currentClass, X10ClassType superClass, TypeSystem xts) { ClassifiedStream h = sw.header(); List<ClassMember> members = n.members(); ITable itable = context.getITable(currentClass); h.write("public:"); h.newline(); h.write("RTT_H_DECLS_INTERFACE"); h.newline(); h.forceNewline(); sw.begin(0); for (PropertyDecl p : context.classProperties()) { n.print(p, sw, tr); } h.write("template <class I> struct itable {"); h.newline(4); h.begin(0); h.write("itable("); boolean firstMethod = true; for (MethodInstance meth : itable.getMethods()) { if (!firstMethod) { h.write(", "); } firstMethod = false; itable.emitFunctionPointerDecl(h, emitter, meth, "I", true); } h.write(") "); firstMethod = true; for (MethodInstance meth : itable.getMethods()) { if (firstMethod) { h.write(": "); firstMethod = false; } else { h.write(", "); } String name = itable.mangledName(meth); h.write(name+"("+name+")"); } h.write(" {}"); h.newline(); firstMethod = true; for (MethodInstance meth : itable.getMethods()) { if (!firstMethod) h.newline(); firstMethod = false; itable.emitFunctionPointerDecl(h, emitter, meth, "I", true); h.write(";"); } h.end(); h.newline(); h.write("};"); h.newline(); h.forceNewline(); // Static methods that encapsulate itable lookup and invocation for (MethodInstance meth : itable.getMethods()) { String mname = itable.mangledName(meth); // Method for x10::lang::Reference (objects, closures, boxed structs) h.write("static "+Emitter.translateType(meth.returnType(), true)); h.write(" "+mname+"("+Emitter.translateType(currentClass, true)+" _recv"); int argNum=0; for (Type f : meth.formalTypes()) { h.write(", "); h.write(Emitter.translateType(f, true)+" arg"+(argNum++)); } h.write(") {"); h.newline(4); h.begin(0); h.writeln("x10::lang::Reference* _refRecv = reinterpret_cast<x10::lang::Reference*>(_recv);"); boolean needsCast = false; if (!meth.returnType().isVoid()) { h.write("return "); // the cast is because our generated member function may use a more general // return type and c++ does not support covariant smartptr returns // TODO: See TODO in CastInjector. Type ret_type = emitter.findRootMethodReturnType(meth.x10Def(), null, meth); needsCast = !xts.typeDeepBaseEquals(meth.returnType(), ret_type, context); if (needsCast) { h.write(selectUncheckedCast(xts, ret_type, meth.returnType())); h.write(chevrons(Emitter.translateType(meth.returnType(), true))); h.write("("); } } h.write("(_refRecv->*(x10aux::findITable"+chevrons(Emitter.translateType(currentClass, false))+"(_refRecv->_getITables())->"+mname+"))("); boolean first = true; argNum = 0; for (Type f : meth.formalTypes()) { if (!first) h.write(", "); h.write("arg"+(argNum++)); first = false; } if (needsCast) h.write(")"); h.write(");"); h.end(); h.newline(); h.writeln("}"); // Method for unboxed structs that are not C++ built-in primitives h.write("template <class R> static "+Emitter.translateType(meth.returnType(), true)); h.write(" "+mname+"(R _recv"); argNum=0; for (Type f : meth.formalTypes()) { h.write(", "); h.write(Emitter.translateType(f, true)+" arg"+(argNum++)); } h.write(") {"); h.newline(4); h.begin(0); if (!meth.returnType().isVoid()) h.write("return "); h.write("_recv->"+Emitter.mangled_method_name(meth.name().toString())+"("); argNum = 0; first = true; for (Type f : meth.formalTypes()) { if (!first) h.write(", "); h.write("arg"+(argNum++)); first = false; } h.write(");"); h.end(); h.newline(); h.writeln("}"); } if (!members.isEmpty()) { String className = Emitter.translateType(currentClass); for (ClassMember member : members) { if (! (member instanceof polyglot.ast.MethodDecl)){ n.printBlock(member, sw, tr); } } } sw.end(); sw.newline(); } private void visitClassBody(ClassBody_c n, X10CPPContext_c context, X10ClassType currentClass, X10ClassType superClass, TypeSystem xts) { ClassifiedStream h = sw.header(); h.write("public:"); h.newline(); h.write("RTT_H_DECLS_CLASS"); h.newline(); h.forceNewline(); sw.begin(0); for (PropertyDecl p : context.classProperties()) { n.print(p, sw, tr); } List<ClassMember> members = n.members(); generateITablesForClass(currentClass, context, xts, "virtual ", h); if (currentClass.isSubtype(xts.Mortal(), context)) { h.write("virtual x10_boolean _isMortal() { return true; }"); h.newline(); h.forceNewline(); } if (!members.isEmpty()) { String className = Emitter.translateType(currentClass); generateUsingDeclsForInheritedMethods(context, currentClass, superClass, xts, h, members); ClassMember prev = null; for (ClassMember member : members) { if ((member instanceof polyglot.ast.CodeDecl) || (prev instanceof polyglot.ast.CodeDecl)) { h.newline(0); sw.newline(0); } prev = member; n.printBlock(member, sw, tr); } emitter.generateClassSerializationMethods(currentClass, sw); } sw.end(); sw.newline(); } private void visitStructBody(ClassBody_c n, X10CPPContext_c context, X10ClassType currentClass, X10ClassType superClass, TypeSystem xts) { assert superClass==null : "Struct cannot have a superclass! superClass="+superClass; ClassifiedStream h = sw.header(); String StructCType = Emitter.translateType(currentClass, false); X10ClassDef cd = currentClass.x10Def(); h.writeln("public:"); h.write("RTT_H_DECLS_STRUCT"); h.newline(); h.forceNewline(); h.write(StructCType+"* operator->() { return this; }"); h.newline(); h.forceNewline(); sw.begin(0); for (PropertyDecl p : context.classProperties()) { n.print(p, sw, tr); } List<ClassMember> members = n.members(); generateITablesForStruct(currentClass, context, xts, h); // create static _alloc method h.newline(); h.write("static " +StructCType+ " " +SharedVarsMethods.ALLOC+ "(){" +StructCType+ " t; return t; }"); h.newline(); h.forceNewline(); if (!members.isEmpty()) { ClassMember prev = null; for (ClassMember member : members) { if ((member instanceof polyglot.ast.CodeDecl) || (prev instanceof polyglot.ast.CodeDecl)) { h.newline(0); sw.newline(0); } prev = member; n.printBlock(member, sw, tr); } emitter.generateStructSerializationMethods(currentClass, sw); sw.forceNewline(); } } private void generateITablesForClass(X10ClassType currentClass, X10CPPContext_c context, TypeSystem xts, String maybeVirtual, ClassifiedStream h) { X10ClassDef cd = currentClass.x10Def(); List<X10ClassType> allInterfaces = xts.allImplementedInterfaces(currentClass); int numInterfaces = allInterfaces.size(); if (numInterfaces > 0 && !currentClass.flags().isAbstract()) { /* ITables declarations */ h.write("static x10aux::itable_entry _itables["+(numInterfaces+1)+"];"); h.newline(); h.forceNewline(); h.write(maybeVirtual+"x10aux::itable_entry* _getITables() { return _itables; }"); h.newline(); h.forceNewline(); int itableNum = 0; for (Type interfaceType : allInterfaces) { ITable itable = context.getITable((X10ClassType) Types.baseType(interfaceType)); itable.emitITableDecl(currentClass, itableNum, emitter, h); itableNum += 1; h.forceNewline(); } /* ITables initialization */ itableNum = 0; for (Type interfaceType : allInterfaces) { ITable itable = context.getITable((X10ClassType) Types.baseType(interfaceType)); itable.emitITableInitialization(currentClass, itableNum, this, h, sw); itableNum += 1; } emitter.printTemplateSignature(cd.typeParameters(), sw); sw.write("x10aux::itable_entry "+Emitter.translateType(currentClass)+"::_itables["+(numInterfaces+1)+"] = {"); itableNum = 0; for (Type interfaceType : allInterfaces) { sw.write("x10aux::itable_entry(&x10aux::getRTT"+chevrons(Emitter.translateType(interfaceType, false))+", &_itable_"+itableNum+"), "); itableNum += 1; } sw.write("x10aux::itable_entry(NULL, (void*)x10aux::getRTT"+chevrons(Emitter.translateType(currentClass, false))+"())};"); sw.newline(); } } private void generateITablesForStruct(X10ClassType currentClass, X10CPPContext_c context, TypeSystem xts, ClassifiedStream h) { X10ClassDef cd = currentClass.x10Def(); List<X10ClassType> allInterfaces = xts.allImplementedInterfaces(currentClass); int numInterfaces = allInterfaces.size(); if (numInterfaces > 0 && !currentClass.flags().isAbstract()) { String thunkBaseName = Emitter.translateFQN(currentClass.fullName().toString()); String thunkParams = ""; if (cd.typeParameters().size() != 0) { String args = ""; int s = cd.typeParameters().size(); for (Type t: cd.typeParameters()) { args += Emitter.translateType(t, true); // type arguments are always translated as refs if (--s > 0) args +=", "; } thunkParams = chevrons(args); } /* ITables declarations */ h.writeln("static x10aux::itable_entry _itables["+(numInterfaces+1)+"];"); h.forceNewline(); h.writeln("x10aux::itable_entry* _getITables() { return _itables; }"); h.forceNewline(); int itableNum = 0; for (Type interfaceType : allInterfaces) { ITable itable = context.getITable((X10ClassType) Types.baseType(interfaceType)); itable.emitITableDecl(currentClass, itableNum, emitter, h); itableNum += 1; h.forceNewline(); } h.writeln("static x10aux::itable_entry _iboxitables["+(numInterfaces+1)+"];"); h.forceNewline(); h.writeln("x10aux::itable_entry* _getIBoxITables() { return _iboxitables; }"); h.forceNewline(); /* ITables initialization */ itableNum = 0; for (Type interfaceType : allInterfaces) { ITable itable = context.getITable((X10ClassType) Types.baseType(interfaceType)); itable.emitITableInitialization(currentClass, itableNum, this, h, sw); itableNum += 1; } String clsCType = Emitter.translateType(currentClass, false); // Itables init for the struct itself emitter.printTemplateSignature(cd.typeParameters(), sw); sw.write("x10aux::itable_entry "+clsCType+"::_itables["+(numInterfaces+1)+"] = {"); itableNum = 0; for (Type interfaceType : allInterfaces) { sw.write("x10aux::itable_entry(&x10aux::getRTT"+chevrons(Emitter.translateType(interfaceType, false))+", &"+ thunkBaseName+thunkParams+"::_itable_"+itableNum+"), "); itableNum += 1; } sw.write("x10aux::itable_entry(NULL, (void*)x10aux::getRTT"+chevrons(Emitter.translateType(currentClass, false))+"())};"); sw.newline(); // ITables init for the IBox thunk. emitter.printTemplateSignature(cd.typeParameters(), sw); sw.write("x10aux::itable_entry "+clsCType+"::_iboxitables["+(numInterfaces+1)+"] = {"); itableNum = 0; for (Type interfaceType : allInterfaces) { sw.write("x10aux::itable_entry(&x10aux::getRTT"+chevrons(Emitter.translateType(interfaceType, false))+", &"+ thunkBaseName+"_ibox"+itableNum+thunkParams+"::itable), "); itableNum += 1; } sw.write("x10aux::itable_entry(NULL, (void*)x10aux::getRTT"+chevrons(Emitter.translateType(currentClass, false))+"())};"); sw.newline(); } } // The goal of this method is for each methodName declared in the childClass, // determine if there is any superclass such that the superclass also declares // methods with that name such that some superclass methods are not overridden // in the subclass. When that happens, we need to emit a using directive because // overriding/overloading is defined differently in C++ than in X10 (or Java). // By emitting the using directive, we pull the superclass methods into the subclass // namespace and thus get the X10/Java semantics. // The alternative to using "using" is to generate proxy methods that forward to the superclass // method. This results in slightly less efficient generated code, but more importantly is // significantly more complex to implement correctly. private void generateUsingDeclsForInheritedMethods(X10CPPContext_c context, X10ClassType childClass, X10ClassType superClass, TypeSystem xts, ClassifiedStream h, List<ClassMember> members) { boolean didSomething = false; Set<Name> possibleNames = CollectionFactory.newHashSet(); for (MethodInstance mi : childClass.methods()) { possibleNames.add(mi.name()); } while (superClass != null && !possibleNames.isEmpty()) { didSomething = generateUsingDeclsHelper(context, childClass, superClass, h, didSomething, possibleNames); superClass = (X10ClassType)superClass.superClass(); } if (!possibleNames.isEmpty()) { // also check for methods of Any; at the impl level these are inherited from X10Class // and therefore need to be treated just as if they were inherited from a real X10 superclass // for the purposes of generating using declarations. didSomething = generateUsingDeclsHelper(context, childClass, xts.Any(), h, didSomething, possibleNames); } if (didSomething) h.forceNewline(); } private boolean generateUsingDeclsHelper(X10CPPContext_c context, X10ClassType childClass, X10ClassType superClass, ClassifiedStream h, boolean didSomething, Set<Name> possibleNames) { Iterator<Name> names = possibleNames.iterator(); nameLoop: while (names.hasNext()) { Name methName = names.next(); List<MethodInstance> childImpls = childClass.methodsNamed(methName); List<MethodInstance> parentImpls = superClass.methodsNamed(methName); if (!parentImpls.isEmpty()) { boolean emitUsing = false; if (childImpls.size() != parentImpls.size()) { // Number of implementation differs, so we can't have an exact signature match. emitUsing = true; } else { // Same number of impls, now check for identical signatures. implLoop: for (MethodInstance childImpl : childImpls) { for (MethodInstance parentImpl : parentImpls) { if (childImpl.isSameMethod(parentImpl, context)) continue implLoop; } // If we get to here, then there is a childImpl that has a different signature than all parentImpls emitUsing = true; break implLoop; } } if (emitUsing) { names.remove(); if (superClass.isAny()) { h.writeln("using "+CLASS_TYPE+"::"+mangled_method_name(methName.toString())+";"); } else { h.writeln("using "+Emitter.translateType(superClass,false)+"::"+mangled_method_name(methName.toString())+";"); } didSomething = true; continue nameLoop; } } } return didSomething; } public void visit(PackageNode_c n) { assert (false); sw.write(mangled_non_method_name(translateFQN(n.package_().get().fullName().toString()))); } public void visit(Import_c n) { assert (false); } public static void processMain(X10ClassType container, CodeWriter sw, X10CPPCompilerOptions options) { TypeSystem xts = container.typeSystem(); if (container.isClass()) container = getStaticMemberContainer(container.x10Def()); String typeString = Emitter.translateType(container); sw.write("#include <"+MessagePassingCodeGenerator.getHeader(container)+">"); sw.newline(); Emitter.dumpString(createMainStub(typeString, options), sw); sw.newline(0); } public static String createMainStub(String container, X10CPPCompilerOptions options) { StringBuilder sb = new StringBuilder(); sb.append("#include <x10aux/bootstrap.h>\n"); String mainTypeArgs = container; sb.append("extern \"C\" { int main(int ac, char **av) { return x10aux::template_main"+chevrons(mainTypeArgs)+"(ac,av); } }\n"); if (options.x10_config.DEBUG) { sb.append("\n// Debugger stuff\n"); sb.append("#include<x10aux/place_local.h>\n"); sb.append("#include<x10/lang/Thread.h>\n"); sb.append("void* x10aux_place_local__fastData = &x10aux::place_local::_fastData;\n"); sb.append("void* __x10MainRef = (void *) "+container+"::main;\n"); sb.append("pthread_key_t* __x10ThreadMapper = (pthread_key_t *) &x10::lang::Thread::__thread_mapper;\n"); sb.append("x10_boolean* __x10ThreadMapperInited = (x10_boolean *) &x10::lang::Thread::__thread_mapper_inited;\n"); } return sb.toString(); } public static final QName HEADER_ANNOTATION = QName.make("x10.compiler.Header"); public void visit(X10MethodDecl_c dec) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = tr.typeSystem(); Flags flags = dec.flags().flags(); String nativePat = null; X10MethodDef def = dec.methodDef(); if (flags.isNative()) { if (!flags.isStatic()) { // Must generate bodies for non-static @Native methods so // that virtual dispatch actually works. nativePat = getCppImplForDef(dec.methodDef()); } if (nativePat == null) return; } if (query.isMainMethod(def)) { ((X10CPPJobExt) tr.job().ext()).addMainMethod(def); } MethodInstance mi = def.asInstance(); X10ClassType container = (X10ClassType) mi.container(); ClassifiedStream h = sw.header(); if ((container.x10Def().typeParameters().size() != 0) && flags.isStatic()) { context.pendingStaticDecls().add(dec); return; } int mid = getUniqueId_().intValue(); ClassifiedStream saved_closure_stream = context.closures; if (def.typeParameters().size() != 0) { sw.pushCurrentStream(context.genericFunctions); context.closures = context.genericFunctionClosures; String guard = getHeaderGuard(getHeader(mi.container().toClass())); sw.write("#ifndef "+guard+"_"+Emitter.mangled_method_name(mi.name().toString())+"_"+mid); sw.newline(); sw.write("#define "+guard+"_"+Emitter.mangled_method_name(mi.name().toString())+"_"+mid); sw.newline(); } // we sometimes need to use a more general return type as c++ does not support covariant smartptr return types Type ret_type = emitter.findRootMethodReturnType(def, dec.position(), mi); String methodName = mi.name().toString(); boolean inlineInClassDecl = false; boolean inlineDirective = false; try { Type annotation = xts.systemResolver().findOne(HEADER_ANNOTATION); if (!((X10Ext) dec.ext()).annotationMatching(annotation).isEmpty()) { if (container.x10Def().typeParameters().size() == 0) { inlineInClassDecl = true; } else { inlineDirective = true; } } } catch (SemanticException e) { /* Ignore exception when looking for annotation */ } // Attempt to make it easy for the post compiler to inline trivial struct methods // by putting them in the h stream instead of the sw stream whenever possible. // Don't bother doing this for generic structs the body stream is already in the header file. if (!flags.isNative() && !inlineInClassDecl && container.isX10Struct() && container.x10Def().typeParameters().size() == 0) { StructMethodAnalyzer analyze = new StructMethodAnalyzer(tr.job(), xts, tr.nodeFactory(), container); dec.visit(analyze.begin()); inlineInClassDecl = analyze.canGoInHeaderStream(); } sw.pushCurrentStream(h); emitter.printHeader(dec, sw, tr, methodName, ret_type, false, false); if (!inlineInClassDecl) { sw.popCurrentStream(); h.write(";"); h.newline(); } if (flags.isNative() || dec.body() != null) { if (!flags.isStatic()) { VarInstance<?> ti = xts.localDef(Position.COMPILER_GENERATED, Flags.FINAL, Types.ref(container), Name.make(THIS)).asInstance(); context.addVariable(ti); } if (!inlineInClassDecl) { emitter.printHeader(dec, sw, tr, methodName, ret_type, true, inlineDirective); } if (flags.isNative()) { assert nativePat != null; sw.write("{"); sw.newline(4); sw.begin(0); if (!dec.returnType().type().isVoid()) sw.write("return "); String target = container.isX10Struct() ? STRUCT_THIS : THIS; List<String> params = new ArrayList<String>(); List<String> args = new ArrayList<String>(); int counter = 0; for (LocalInstance f : mi.formalNames()) { Type fType = mi.formalTypes().get(counter); params.add(f.name().toString()); args.add(f.name().toString()); counter++; } List<Type> classTypeArguments = Collections.<Type>emptyList(); List<ParameterType> classTypeParams = Collections.<ParameterType>emptyList(); emitNativeAnnotation(nativePat, mi.x10Def().typeParameters(), mi.typeParameters(), target, params, args, classTypeParams, classTypeArguments); sw.write(";"); sw.end(); sw.newline(); sw.writeln("}"); } else { dec.printSubStmt(dec.body(), sw, tr); } sw.newline(); } else { // Define property getter methods. if (flags.isProperty() && flags.isAbstract() && mi.formalTypes().size() == 0 && mi.typeParameters().size() == 0) { X10FieldInstance fi = (X10FieldInstance) container.fieldNamed(mi.name()); if (fi != null) { //assert (X10Flags.toX10Flags(fi.flags()).isProperty()); // FIXME: property fields don't seem to have the property flag set // This is a property method in an interface. Give it a body. if (!inlineInClassDecl) { emitter.printHeader(dec, sw, tr, methodName, ret_type, true, inlineDirective); } sw.write(" {"); sw.allowBreak(0, " "); sw.write("return "+mangled_field_name(fi.name().toString())+";"); sw.allowBreak(0, " "); sw.write("}"); } } } if (inlineInClassDecl) { sw.popCurrentStream(); } if (def.typeParameters().size() != 0) { sw.popCurrentStream(); String guard = getHeaderGuard(getHeader(mi.container().toClass())); context.genericFunctions.writeln("#endif // "+guard+"_"+Emitter.mangled_method_name(mi.name().toString())+"_"+mid); } context.closures = saved_closure_stream; } public void visit(ConstructorDecl_c dec) { // [DC] here we generate a pair of functions to form a fake // constructor. Real constructors are no use to us because they // cannot invoke virtual functions with the semantics we need. The two // functions are _make which behaves like a constructor by creating an // uninitialised object and calling _constructor (the body of the X10 // constructor). Calls to super() and this() are translated into calls // to the appropriate OtherClass::_constructor (hence the separate // function). X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (dec.flags().flags().isNative()) return; ClassifiedStream h = sw.header(); X10ClassType container = (X10ClassType) dec.constructorDef().container().get(); String typeName = Emitter.translateType(container.def().asType()); TypeSystem xts = (TypeSystem)context.typeSystem(); boolean inlineInClassDecl = false; try { Type annotation = xts.systemResolver().findOne(HEADER_ANNOTATION); if (!((X10Ext) dec.ext()).annotationMatching(annotation).isEmpty()) { inlineInClassDecl = true; } } catch (SemanticException e) { /* Ignore exception when looking for annotation */ } // Attempt to make it easy for the post compiler to inline trivial struct constructors // by putting them in the h stream instead of the sw stream whenever possible. if (!inlineInClassDecl && container.isX10Struct()) { StructMethodAnalyzer analyze = new StructMethodAnalyzer(tr.job(), xts, tr.nodeFactory(), container); dec.visit(analyze.begin()); inlineInClassDecl = analyze.canGoInHeaderStream(); } sw.pushCurrentStream(h); emitter.printHeader(dec, sw, tr, false, false, "void"); if (!inlineInClassDecl) { h.write(";") ; h.newline(); h.forceNewline(); sw.popCurrentStream(); emitter.printHeader(dec, sw, tr, true, false, "void"); } X10ConstructorInstance ci = (X10ConstructorInstance) dec.constructorDef().asInstance(); if (dec.body() == null) { assert false : dec.position().toString(); sw.write("{ }"); sw.newline(); sw.forceNewline(); } assert (!dec.flags().flags().isStatic()); TypeSystem ts = tr.typeSystem(); VarInstance<?> ti = ts.localDef(Position.COMPILER_GENERATED, Flags.FINAL, Types.ref(container), Name.make(THIS)).asInstance(); context.addVariable(ti); dec.printSubStmt(dec.body(), sw, tr); sw.newline(); if (inlineInClassDecl) { sw.popCurrentStream(); } if (!container.flags().isAbstract()) { int _makeStartLine = sw.currentStream().getStreamLineNumber(); // emit _make method h.write("static "); sw.pushCurrentStream(h); emitter.printHeader(dec, sw, tr, false, true, container.isX10Struct() ? typeName : make_ref(typeName)); if (!inlineInClassDecl) { h.write(";") ; h.newline(); h.forceNewline(); sw.popCurrentStream(); _makeStartLine = sw.currentStream().getStreamLineNumber(); emitter.printHeader(dec, sw, tr, true, true, container.isX10Struct() ? typeName : make_ref(typeName)); } sw.allowBreak(0, " "); sw.write("{"); sw.newline(4); sw.begin(0); if (container.isX10Struct()) { sw.write(typeName+" this_; "); sw.newline(); } else { // XTENLANG-1407: Remove this memset call once we finish the default value specification/implementation. // Expect it to be more efficient to explicitly initialize all of the object fields instead // of first calling memset, then storing into most of the fields a second time. sw.write(make_ref(typeName)+" this_ = "+ "new (memset(x10aux::alloc"+chevrons(typeName)+"(), 0, sizeof("+typeName+"))) "+typeName+"();"); sw.newline(); } sw.write("this_->"+CONSTRUCTOR+"("); for (Iterator<Formal> i = dec.formals().iterator(); i.hasNext(); ) { Formal f = i.next(); sw.write(mangled_non_method_name(f.name().id().toString())); if (i.hasNext()) { sw.write(","); sw.allowBreak(0, " "); } } sw.writeln(");"); sw.write("return this_;"); sw.end(); sw.newline(); sw.writeln("}"); sw.forceNewline(); sw.currentStream().omitLines(sw.currentStream().getStreamLineNumber() - _makeStartLine + 1); if (inlineInClassDecl) { sw.popCurrentStream(); } } sw.newline(); sw.forceNewline(); } private String embeddedName(Name name) { return "_Embed_"+mangled_non_method_name(name.toString()); } public void visit(FieldDecl_c dec) { // FIXME: HACK: skip synthetic serialization fields if (query.isSyntheticField(dec.name().id().toString())) return; X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = context.typeSystem(); // Generate nothing for @Native fields; all references will be substituted with the @Native expr if (getCppImplForDef((X10FieldDef)dec.fieldDef()) != null) { return; } X10ClassType declaringClass = (X10ClassType)dec.fieldDef().asInstance().container(); boolean isStatic = dec.flags().flags().isStatic(); if ((((X10ClassDef)declaringClass.def()).typeParameters().size() != 0) && isStatic) { // Static fields of generic classes get deferred to the void specialization of the class context.pendingStaticDecls().add(dec); return; } ClassifiedStream h = sw.header(); sw.pushCurrentStream(h); boolean embed = !((X10Ext)dec.ext()).annotationMatching(xts.Embed()).isEmpty(); if (embed) { String tmpName = embeddedName(dec.name().id()); sw.writeln(Emitter.translateType(dec.type().type(), false)+" "+tmpName+";"); } emitter.printHeader(dec, sw, tr, false); sw.writeln(";"); sw.popCurrentStream(); if (isStatic) { String container = Emitter.translateType(dec.fieldDef().asInstance().container()); generateStaticFieldSupportCode(dec, container, sw); } h.newline(); h.forceNewline(); } private static final String STATIC_FIELD_ACCESSOR_SUFFIX = "__get"; private static final String STATIC_FIELD_STATUS_SUFFIX = "__status"; private static final String STATIC_FIELD_EXCEPTION_SUFFIX = "__exception"; private static final String STATIC_FIELD_INITIALIZER_SUFFIX = "__init"; private static final String STATIC_FIELD_REAL_INIT_SUFFIX = "__do_init"; private static final String STATIC_FIELD_UNINITIALIZED = "x10aux::StaticInitController::UNINITIALIZED"; private static final String STATIC_FIELD_INITIALIZING = "x10aux::StaticInitController::INITIALIZING"; private static final String STATIC_FIELD_INITIALIZED = "x10aux::StaticInitController::INITIALIZED"; private static final String STATIC_FIELD_EXCEPTIONAL = "x10aux::StaticInitController::EXCEPTION_RAISED"; /** * Generate an initializer method for a given field declaration. */ private void generateStaticFieldInitializer(FieldDecl_c dec, String container, StreamWrapper sw) { String name = dec.name().id().toString(); String fname = mangled_field_name(name); String status = mangled_field_name(name+STATIC_FIELD_STATUS_SUFFIX); String except = mangled_field_name(name+STATIC_FIELD_EXCEPTION_SUFFIX); String init_nb = mangled_field_name(name+STATIC_FIELD_REAL_INIT_SUFFIX); String init = mangled_field_name(name+STATIC_FIELD_INITIALIZER_SUFFIX); ClassifiedStream h = sw.header(); // declare the actual field initializer h.write("static void "); h.write(init_nb); h.writeln("();"); // declare the on-demand field initializer h.write("static void "); h.write(init); h.writeln("();"); // define the actual field initializer // This method is mainly called indirectly from the on-demand field initializer, // but for a few fields is also called from initialize_xrx in bootstrap.cc sw.write("void "); sw.write(container + "::" + init_nb); sw.write("() {"); sw.newline(4); sw.begin(0); // set the status (ok to do here because either we are in single-threaded // mode, or we will have already set the status to INITIALIZING atomically) sw.writeln(status + " = " + STATIC_FIELD_INITIALIZING + ";"); // initialize the field sw.write("_SI_(\"Doing static initialization for field: "+container+"."+name+"\");"); sw.newline(); String val = getId(); emitter.printType(dec.type().type(), sw); sw.allowBreak(2, 2, " ", 1); sw.write(val + " = "+selectUncheckedCast(tr.typeSystem(), dec.init().type(), dec.type().type())); sw.write(chevrons(Emitter.translateType(dec.type().type(), true))+"("); dec.print(dec.init(), sw, tr); sw.writeln(");"); // copy into the field sw.writeln(fname + " = " + val + ";"); // update the status sw.write(status + " = " + STATIC_FIELD_INITIALIZED + ";"); sw.end(); sw.newline(); sw.writeln("}"); // define the on-demand field initializer sw.write("void "); sw.write(container + "::" + init); sw.write("() {"); sw.newline(4); sw.begin(0); sw.writeln("x10aux::StaticInitController::initField(&" + status+", &"+init_nb+", &"+except+", \""+container+"."+name+"\");"); sw.end(); sw.newline(); sw.writeln("}"); } /** * Generates the accessor method and the initialization flag for a given * field declaration. */ private void generateStaticFieldSupportCode(FieldDecl_c dec, String container, StreamWrapper sw) { String name = dec.name().id().toString(); TypeSystem xts = tr.typeSystem(); ClassifiedStream h = sw.header(); String fname = mangled_field_name(name); String status = mangled_field_name(name+STATIC_FIELD_STATUS_SUFFIX); String accessor = mangled_field_name(name+STATIC_FIELD_ACCESSOR_SUFFIX); String init = mangled_field_name(name+STATIC_FIELD_INITIALIZER_SUFFIX); String except = mangled_field_name(name+STATIC_FIELD_EXCEPTION_SUFFIX); // define the field. emitter.printType(dec.type().type(), sw); sw.allowBreak(2, " "); sw.write(container+"::"); sw.write(mangled_field_name(dec.name().id().toString())); sw.writeln(";"); generateStaticFieldInitializer(dec, container, sw); // declare the initialization flag h.writeln("static volatile x10aux::StaticInitController::status "+status+";");; // declare the exception holder h.writeln("static "+make_ref("x10::lang::CheckedThrowable")+" "+except+";");; // declare the accessor method h.write("static "); emitter.printType(dec.type().type(), h); h.allowBreak(2, 2, " ", 1); h.write(accessor); h.writeln("();"); // define the accessor method X10CPPContext_c context = (X10CPPContext_c) tr.context(); ClassifiedStream gh = context.genericFunctions; gh.write("inline "); emitter.printType(dec.type().type(), gh); gh.allowBreak(2, 2, " ", 1); gh.write(container+"::"+accessor); gh.write("() {"); gh.newline(4); gh.begin(0); gh.write("if ("+status+" != " + STATIC_FIELD_INITIALIZED + ") {"); gh.newline(4); gh.begin(0); gh.write(init + "();"); gh.end(); gh.newline(); gh.write("}"); gh.newline(); gh.write("return "); gh.write(container+"::"); gh.write(fname); gh.write(";"); gh.end(); gh.newline(); gh.write("}"); gh.newline(); gh.forceNewline(); // define the initialization flag sw.write("volatile x10aux::StaticInitController::status "); sw.write(container+"::"); sw.write(status); sw.writeln(";"); // define the exception holder flag sw.write(make_ref("x10::lang::CheckedThrowable")+" "); sw.write(container+"::"); sw.write(except); sw.writeln(";"); } public void visit(PropertyDecl_c n) { super.visit(n); } public void visit(Initializer_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (n.flags().flags().isStatic()) { assert (false) : ("Static initializer alert!"); } if (((X10ClassDef) context.currentClassDef()).typeParameters().size() != 0 && n.flags().flags().isStatic()) { context.pendingStaticDecls().add(n); return; } else { // Ignore -- this will have been processed earlier } } public void visit(AssignPropertyCall_c n) { List<X10FieldInstance> definedProperties = n.properties(); List<Expr> arguments = n.arguments(); int aSize = arguments.size(); assert (definedProperties.size() == aSize); for (int i = 0; i < aSize; i++) { Expr arg = arguments.get(i); FieldInstance fi = definedProperties.get(i); sw.write(mangled_field_name(fi.name().toString())); sw.write(" = "); n.print(arg, sw, tr); sw.write(";"); sw.newline(); } } public void visit(Assert_c n) { if (!tr.job().extensionInfo().getOptions().assertions) return; sw.write("#ifndef NO_ASSERTIONS"); sw.newline(); sw.write("if (x10aux::x10__assertions_enabled)"); sw.newline(4); sw.begin(0); sw.write("x10aux::x10__assert("); n.print(n.cond(), sw, tr); if (n.errorMessage() != null) { sw.write(","); sw.allowBreak(4, " "); n.print(n.errorMessage(), sw, tr); } sw.write(");"); sw.end(); sw.newline(); sw.write("#endif//NO_ASSERTIONS"); sw.newline(); } public void visit(Switch_c n) { sw.write("switch ("); if (n.expr().type().isChar()) { sw.write("("); n.print(n.expr(), sw, tr); sw.write(").v"); } else { n.print(n.expr(), sw, tr); } sw.write(")"); sw.allowBreak(0, " "); sw.write("{"); sw.newline(); if (n.elements().size() > 0) { sw.newline(4); sw.begin(0); for (SwitchElement s : n.elements()) { n.print(s, sw, tr); } sw.end(); sw.newline(0); } else sw.write(" "); sw.write("}"); } public void visit(SwitchBlock_c n) { sw.write("{"); if (n.statements().size() > 0) { sw.newline(4); sw.begin(0); for (Iterator<Stmt> i = n.statements().iterator(); i.hasNext(); ) { Stmt s = i.next(); n.print(s, sw, tr); if (i.hasNext()) sw.newline(); } sw.end(); sw.newline(0); } else sw.write(" "); sw.write("}"); } public void visit(Case_c n) { sw.newline(); if (n.expr() == null) { sw.write("default: ;"); // Add gratuitous ; to avoid post-compiler failure if default is last one in switch and is empty. } else { sw.write("case "); // FIXME: [IP] HACK HACK HACK! Substitute the actual constant if any // FIXME: [IP] Even worse hack: ignore @Native on const fields when used in switches. if (n.expr() instanceof Field_c && n.expr().isConstant()) { sw.write(""+n.expr().constantValue()); sw.write("/"+"*"); n.print(n.expr(), sw, tr); sw.write("*"+"/"); } else if (n.expr() instanceof CharLit_c) { CharLit_c lit = (CharLit_c)n.expr(); sw.write("'"+StringUtil.escape(lit.value())+"'"); } else { n.print(n.expr(), sw, tr); } sw.write(": ;"); // Add gratituous ; to avoid post-compiler failure if case is last one in switch and is empty. } sw.newline(); } public void visit(Branch_c br) { if (br.labelNode() != null) { if (br.kind() == Branch_c.CONTINUE) sw.write("goto " + br.labelNode().id() + "_next_"); else sw.write("goto " + br.labelNode().id() + "_end_"); } else sw.write(br.kind().toString()); sw.write(";"); } private void printLabel(String label, CodeWriter w) { w.write("goto " + label + "; "); w.write(label + ":"); } public void visit(Labeled_c label) { // For every labeled statement, generate one/three labels-> // L: S --> L : // S // If S is a for / while / do-while loop then after the // generated C++ for-loop, have a label L_end_ and before // end-parenthesis of the loop, have one more label L_next_: // L : for (...) { ... } --> // L : // for (...) {... L_next_: ; } // L_end_: ; X10CPPContext_c context = (X10CPPContext_c) tr.context(); printLabel(label.labelNode().id().toString(), sw); sw.write(" "); context.setLabel(label.labelNode().id().toString(), label.statement()); label.print(label.statement(), sw, tr); sw.newline(); } public void visit(Assign_c asgn) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); boolean unsigned_op = false; String opString = asgn.operator().toString(); TypeSystem xts = tr.typeSystem(); // TODO // // Boolean short-circuiting operators are ok // Assign_c n = asgn; // assert (opString.equals("&&") || opString.equals("||")) // : "visiting "+n.getClass()+" at "+n.position()+": "+n; if (opString.equals(">>>=")) { unsigned_op = true; opString = opString.substring(1); } Expr lhs = asgn.left(); Expr rhs = asgn.right(); if (unsigned_op) { sw.write("("+Emitter.translateType(asgn.type())+")("); sw.write("(("+emitter.makeUnsignedType(lhs.type())+"&)"); } asgn.printSubExpr(lhs, false, sw, tr); if (unsigned_op) sw.write(")"); sw.write(" "); if (asgn.operator() != Assign_c.ASSIGN) { assert (false); sw.write("/"+"*"+" op= "+"*"+"/"); sw.write(" "); } // [IP] Are all the operators the same? sw.write(opString); sw.allowBreak(2, 2, " ", 1); if (unsigned_op) sw.write("(("+emitter.makeUnsignedType(rhs.type())+")"); Boolean embed = false; if (asgn instanceof FieldAssign) { FieldInstance fi = ((FieldAssign) asgn).fieldInstance(); if (!((X10FieldInstance) fi).annotationsMatching(tr.typeSystem().Embed()).isEmpty()) { embed = true; } } if (embed && !xts.isStructType(rhs.type())) { FieldInstance fi = ((FieldAssign) asgn).fieldInstance(); if (rhs instanceof StmtExpr_c && ((StmtExpr_c) rhs).statements().size()>=2 && ((StmtExpr_c) rhs).statements().get(1) instanceof ConstructorCall_c) { // rhs is split constructor sw.write("&"+embeddedName(fi.name())+";"); sw.newline(); asgn.print(((ConstructorCall_c) ((StmtExpr_c) rhs).statements().get(1)).target(lhs), sw, tr); } else { // rhs is new context.setEmbeddedFieldName(embeddedName(fi.name())); asgn.printSubExpr(rhs, true, sw, tr); context.setEmbeddedFieldName(null); } } else { asgn.printSubExpr(rhs, true, sw, tr); } if (unsigned_op) sw.write("))"); } public void visit(Return_c ret) { Expr e = ret.expr(); if (e == null) { sw.write("return;"); } else { sw.write("return "); boolean needsCast = false; Context context = tr.context(); if (context.currentCode() instanceof X10MethodDef) { X10MethodDef md = (X10MethodDef) context.currentCode(); MethodInstance mi = md.asInstance(); TypeSystem xts = tr.typeSystem(); // the cast is because our generated member function may use a more general // return type because c++ does not support covariant smartptr returns // TODO: See TODO in CastInjector. Type ret_type = emitter.findRootMethodReturnType(md, null, mi); needsCast = !xts.typeDeepBaseEquals(mi.returnType(), ret_type, context); if (needsCast) { sw.write(selectUncheckedCast(xts, mi.returnType(), ret_type)); sw.write(chevrons(Emitter.translateType(ret_type, true)) + "("); } } ret.print(e, sw, tr); if (needsCast) { sw.write(")"); } sw.write(";"); sw.newline(); } } public void visit(Formal_c n) { emitter.printHeader(n, sw, tr, true); } public void visit(LocalDecl_c dec) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = (TypeSystem)context.typeSystem(); boolean stackAllocate = false; Type annotation = xts.StackAllocate(); if (!((X10Ext) dec.ext()).annotationMatching(annotation).isEmpty()) { stackAllocate = true; // System.err.println("@StackAllocate " + dec); } String tmpName = null; if (stackAllocate) { tmpName = "_StackAllocate_"+mangled_non_method_name(dec.name().id().toString()); sw.writeln(Emitter.translateType(dec.type().type(), false)+" "+tmpName+";"); assert context.getStackAllocName() == null; context.setStackAllocName(tmpName); } else { emitter.printHeader(dec, sw, tr, true); } Expr initexpr = dec.init(); if (initexpr != null) { if (!stackAllocate) sw.write(" ="); sw.allowBreak(2, " "); Type aType = dec.type().type(); dec.print(initexpr, sw, tr); } if (stackAllocate) { context.setStackAllocName(null); sw.writeln(";"); emitter.printHeader(dec, sw, tr, true); sw.write("(&"+tmpName+")"); } if (tr.appendSemicolon()) { sw.write(";"); sw.newline(0); } } public void visit(Block_c b) { /* * If this block had a label, it might have Break's in it, so we need * the L_end label at the end, as the Break's get written out as "goto L_end"; */ String label = null; X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (context.getLabeledStatement() == b) { label = context.getLabel(); context.setLabel(null, null); } String s = getCppImplForStmt(b); if (s != null) { sw.write(s); return; } sw.write("{"); sw.newline(); if (label != null) { sw.write("{"); sw.newline(0); sw.begin(0); } if (b.statements().size() > 0) { sw.newline(4); sw.begin(0); for (Iterator<Stmt> i = b.statements().iterator(); i.hasNext(); ) { Stmt n = i.next(); b.printBlock(n, sw, tr); if (i.hasNext()) sw.newline(); } sw.end(); sw.newline(0); } else sw.write(" "); if (label != null) { sw.newline(0); sw.write("}"); printLabel(label + "_end_", sw); sw.write(" ;"); sw.newline(); } sw.newline(); sw.write("}"); } public void visit(StmtSeq_c n) { List<Stmt> stmts = n.statements(); if (stmts.size() == 0) { sw.write(" "); return; } for (Stmt s : stmts) { n.printBlock(s, sw, tr); sw.newline(); } } public void visit(StmtExpr_c n) { X10CPPCompilerOptions opts = (X10CPPCompilerOptions) tr.job().extensionInfo().getOptions(); boolean oldSemiColon = tr.appendSemicolon(true); Expr e = n.result(); sw.write("(__extension__ ({"); sw.newline(4); sw.begin(0); List<Stmt> stmts = n.statements(); boolean oldPrintType = tr.printType(true); for (Stmt stmt : stmts) { n.printBlock(stmt, sw, tr); sw.newline(); } tr.printType(oldPrintType); if (e != null) { n.print(e, sw, tr); sw.write(";"); } sw.end(); sw.newline(); sw.write("}))"); sw.newline(); tr.appendSemicolon(oldSemiColon); } public void visit(For_c n) { // FIXME: Generate normal for-loop code, without // separating out the inits. [Krishna] String label = null; X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (context.getLabeledStatement() == n) { label = context.getLabel(); context.setLabel(null, null); } sw.write("{"); sw.newline(4); sw.begin(0); if (n.inits() != null) { for (ForInit s : n.inits()) { if (s instanceof LocalDecl_c) { LocalDecl_c dec = (LocalDecl_c) s; emitter.printHeader(dec, sw, tr, true); sw.write(";"); sw.newline(0); } } } sw.newline(0); sw.write("for ("); sw.begin(0); if (n.inits() != null) { for (Iterator<ForInit> i = n.inits().iterator(); i.hasNext();) { ForInit s = i.next(); boolean oldSemiColon = tr.appendSemicolon(false); boolean oldPrintType = tr.printType(false); n.printBlock(s, sw, tr); tr.printType(oldPrintType); tr.appendSemicolon(oldSemiColon); if (i.hasNext()) { sw.write(","); sw.allowBreak(2, " "); } } } sw.write(";"); sw.allowBreak(0); if (n.cond() != null) { n.printBlock(n.cond(), sw, tr); } sw.write(";"); sw.allowBreak(0); if (n.iters() != null) { for (Iterator<ForUpdate> i = n.iters().iterator(); i.hasNext(); ) { ForUpdate s = i.next(); boolean oldSemiColon = tr.appendSemicolon(false); n.printBlock(s, sw, tr); tr.appendSemicolon(oldSemiColon); if (i.hasNext()) { sw.write(","); sw.allowBreak(2, " "); } } } sw.end(); sw.write(")"); sw.allowBreak(0, " "); if (label != null) { sw.write("{"); sw.newline(0); sw.begin(0); } Stmt body = n.body(); if (!(body instanceof Block_c)) body = tr.nodeFactory().Block(body.position(), body); n.print(body, sw, tr); if (label != null) { sw.newline(0); printLabel(label + "_next_", sw); sw.write(" ;"); sw.end(); sw.newline(); sw.write("}"); } if (label != null) { sw.newline(0); printLabel(label + "_end_", sw); sw.write(" ;"); } sw.end(); sw.newline(); sw.write("}"); sw.newline(0); } public void visit(Do_c n) { String label = null; X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (context.getLabeledStatement() == n) { label = context.getLabel(); context.setLabel(null, null); } sw.write("do"); sw.allowBreak(0, " "); if (label != null) { sw.write("{"); sw.newline(0); sw.begin(0); } Stmt body = n.body(); if (!(body instanceof Block_c)) body = tr.nodeFactory().Block(body.position(), body); n.print(body, sw, tr); if (label != null) { sw.newline(0); printLabel(label + "_next_", sw); sw.write(" ;"); sw.end(); sw.newline(); sw.write("}"); } sw.allowBreak(0, " "); sw.write("while ("); sw.begin(0); n.printBlock(n.cond(), sw, tr); sw.end(); sw.write(");"); if (label != null) { sw.newline(0); printLabel(label + "_end_", sw); sw.write(" ;"); } sw.newline(0); } public void visit(While_c n) { String label = null; X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (context.getLabeledStatement() == n) { label = context.getLabel(); context.setLabel(null, null); } sw.write("while ("); sw.begin(0); n.printBlock(n.cond(), sw, tr); sw.end(); sw.write(")"); sw.allowBreak(0, " "); if (label != null) { sw.write("{"); sw.newline(4); sw.begin(0); } Stmt body = n.body(); if (!(body instanceof Block_c)) body = tr.nodeFactory().Block(body.position(), body); n.print(body, sw, tr); if (label != null) { sw.newline(0); printLabel(label + "_next_", sw); sw.write(" ;"); sw.end(); sw.newline(); sw.write("}"); } if (label != null) { sw.newline(0); printLabel(label + "_end_", sw); sw.write(" ;"); } sw.newline(0); } public void visit(If_c n) { sw.write("if ("); n.printBlock(n.cond(), sw, tr); sw.write(")"); sw.allowBreak(0, " "); n.print(n.consequent(), sw, tr); if (n.alternative() != null) { sw.allowBreak(0, " "); sw.write("else"); sw.allowBreak(0, " "); // [IP] Semi-HACK: handle "else if" specially Stmt alternative = n.alternative(); if (alternative instanceof Block_c) { Block_c block = (Block_c) alternative; if (block.statements().size() == 1 && block.statements().get(0) instanceof If_c) alternative = (Stmt) block.statements().get(0); } n.print(alternative, sw, tr); } sw.newline(0); } public void visit(Empty_c n) { sw.write(";"); } public void visit(Eval_c n) { boolean semi = tr.appendSemicolon(true); n.print(n.expr(), sw, tr); if (semi) sw.write(";"); tr.appendSemicolon(semi); } private static boolean needsNullCheck(Receiver e) { if (e instanceof X10CanonicalTypeNode_c) return false; if (e instanceof X10Special_c) { if (((X10Special_c) e).qualifier() == null) return false; return !Types.isNonNull(e.type()); } if (e instanceof X10Cast_c) return needsNullCheck(((X10Cast_c) e).expr()); return !Types.isNonNull(e.type()); } public void visit(X10Call_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = tr.typeSystem(); MethodInstance mi = (MethodInstance) n.methodInstance(); Receiver target = n.target(); Type t = target.type(); X10MethodDef md = mi.x10Def(); if (mi.flags().isStatic()) { TypeNode tn = target instanceof TypeNode ? (TypeNode) target : tr.nodeFactory().CanonicalTypeNode(target.position(), t); if (xts.isParameterType(t)) { // Rewrite to the class declaring the field. target = tn.typeRef(md.container()); n = (X10Call_c) n.target(target); t = target.type(); } if (t.isClass()) { X10ClassType ct = (X10ClassType)t.toClass(); target = tn.typeRef(Types.ref(getStaticMemberContainer(ct.x10Def()))); } } Flags flags = mi.flags(); // Check for properties accessed using method syntax. They may have @Native annotations too. if (flags.isProperty() && mi.formalTypes().size() == 0 && mi.typeParameters().size() == 0) { X10FieldInstance fi = (X10FieldInstance) md.container().get().fieldNamed(mi.name()); if (fi != null) { //assert (X10Flags.toX10Flags(fi.flags()).isProperty()); // FIXME: property fields don't seem to have the property flag set // This is a property getter method. Translate as a field access. String pat = getCppImplForDef(fi.x10Def()); if (pat != null) { Map<String,Object> components = new HashMap<String,Object>(); components.put("this", target); components.put("0", target); emitter.nativeSubst("Native", components, tr, pat, sw); return; } } } String lang[] = new String[1]; String pat = getCppImplForDef(md, lang); if (pat != null) { // If the method is static or if the method's container is a struct then we go ahead and inline // the @Native annotation at the callsite. This is safe because there is no virtual dispatch involved. // // If the method's container has a C++ @NativeRep annotation, then we inline the @Native annotation // because we have nothing else we can reasonably do. If the @NativeRep class was written "correctly" // this will not break the semantics because the @Native will forward to the proper virtual dispatch. // // If the pattern is for the "cuda" backend then inline it also, as the CUDA backend does not yet support functions // // Otherwise (virtual method of a non-NativeRep class), we ignore the @Native annotation at the // callsite and generate a normal calling sequence. This preserves virtual method semantics. if (mi.flags().isStatic() || (mi.container().isClass() && ((X10ClassType)mi.container()).isX10Struct()) || (mi.container().isClass() && getCppRep(((X10ClassType)mi.container()).x10Def()) != null) || lang[0].equals("cuda")) { List<String> params = new ArrayList<String>(); for (LocalDef fn : mi.def().formalNames()) { params.add(fn.name().toString()); } List<Type> classTypeArguments = Collections.<Type>emptyList(); List<ParameterType> classTypeParams = Collections.<ParameterType>emptyList(); if (mi.container().isClass() && !mi.flags().isStatic()) { X10ClassType ct = (X10ClassType) mi.container().toClass(); classTypeArguments = ct.typeArguments(); classTypeParams = ct.x10Def().typeParameters(); if (classTypeArguments == null) classTypeArguments = Collections.<Type>emptyList(); if (classTypeParams == null) classTypeParams = Collections.<ParameterType>emptyList(); } emitNativeAnnotation(pat, mi.x10Def().typeParameters(), mi.typeParameters(), target, params, n.arguments(), classTypeParams, classTypeArguments); return; } } // the cast is because our generated member function may use a more general // return type because c++ does not support covariant smartptr returns // TODO: See TODO in CastInjector. Type ret_type = emitter.findRootMethodReturnType(md, null, mi); boolean needsCast = !xts.typeDeepBaseEquals(mi.returnType(), ret_type, context); if (needsCast) { sw.write(selectUncheckedCast(xts, ret_type, mi.returnType())); sw.write(chevrons(Emitter.translateType(mi.returnType(), true)) + "("); } sw.begin(0); String dangling = ""; boolean already_static = false; String targetMethodName = mangled_method_name(n.name().id().toString()); boolean isInterfaceInvoke = false; boolean needsNullCheck = needsNullCheck(target); if (!n.isTargetImplicit()) { // explicit target. if (target instanceof X10Special_c && ((X10Special_c)target).kind().equals(X10Special_c.SUPER)) { sw.write(Emitter.translateType(t)); sw.write("::"); already_static = true; } else if (target instanceof Expr) { if (mi.flags().isStatic()) { sw.write("((void)"); n.printSubExpr((Expr) target, false, sw, tr); sw.write(","); sw.write(Emitter.translateType(t)); sw.write("::"); dangling = ")"; already_static = true; } else { if (t.isClass()) { X10ClassType clsType = (X10ClassType)t.toClass(); if (clsType.flags().isInterface()) { invokeInterface(n, (Expr) target, n.arguments(), make_ref(REFERENCE_TYPE), clsType, mi, needsNullCheck); sw.end(); if (needsCast) { sw.write(")"); } return; // FIXME: unify with the regular return } } else if (xts.isParameterType(t)) { if (mi.container().isClass() && mi.container().toClass().flags().isInterface()) { invokeInterface(n, (Expr) target, n.arguments(), Emitter.translateType(t), mi.container(), mi, true); sw.end(); if (needsCast) { sw.write(")"); } return; // FIXME: unify with the regular return } } boolean assoc = !(target instanceof New_c || target instanceof Binary_c); if (!isInterfaceInvoke) { if (needsNullCheck) sw.write("x10aux::nullCheck("); n.printSubExpr((Expr) target, assoc, sw, tr); if (needsNullCheck) sw.write(")"); sw.write("->"); } } } else if (target instanceof TypeNode || target instanceof AmbReceiver) { n.print(target, sw, tr); sw.write("::"); already_static = true; } } boolean virtual_dispatch = true; if (mi.typeParameters().size() == 0) { // Attempting to devirtualize generic instance methods breaks xlC. // Not clear if this is because we aren't generating the right magic incantation // to do the invocation or if it is a bug in xlC. // Until that is clear, just don't try to do the optimization in this case. if (t.isClass()) { X10ClassType ct = (X10ClassType)t.toClass(); X10ClassDef cd = ct.x10Def(); if (cd.flags().isFinal()) { virtual_dispatch = false; } } if (mi.flags().isFinal()) { virtual_dispatch = false; } } if (!virtual_dispatch && !already_static ) { // disable virtual dispatch sw.write(Emitter.translateType(t)); sw.write("::"); } if (context.inTemplate() && mi.typeParameters().size() != 0) { sw.write("template "); } if (!isInterfaceInvoke) { sw.write(targetMethodName); emitter.printTemplateInstantiation(mi, sw); } sw.write("("); printCallActuals(n, context, xts, mi, n.arguments()); sw.write(")"); sw.write(dangling); sw.end(); if (needsCast) { sw.write(")"); } } private void invokeInterface(Node_c n, Expr target, List<Expr> args, String dispType, Type contType, MethodInstance mi, boolean needsNullCheck) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = tr.typeSystem(); Type rt = mi.returnType(); assert (target != null); // has to be explicit target. assert (contType instanceof X10ClassType); // have to dispatch to an interface type. X10ClassType clsType = (X10ClassType) contType; assert (clsType.flags().isInterface()); // have to dispatch to an interface type. ITable itable= context.getITable(clsType); String targetMethodName = itable.mangledName(mi); sw.write(Emitter.translateType(clsType, false)+"::"+targetMethodName+"("); if (needsNullCheck) sw.write("x10aux::nullCheck("); n.print(target, sw, tr); if (needsNullCheck) sw.write(")"); if (mi.formalTypes().size()>0) sw.write(", "); printCallActuals(n, context, xts, mi, args); sw.write(")"); } private void printCallActuals(Node_c n, X10CPPContext_c context, TypeSystem xts, MethodInstance mi, List<Expr> args) { int counter; if (args.size() > 0) { sw.allowBreak(2, 2, "", 0); // miser mode sw.begin(0); counter = 0; for (Iterator<Expr> i = args.iterator(); i.hasNext(); ) { Expr e = i.next(); n.print(e, sw, tr); if (i.hasNext()) { sw.write(","); sw.allowBreak(0, " "); } counter++; } sw.end(); } } public void visit(Field_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); Receiver target = n.target(); Type t = target.type(); TypeSystem xts = (TypeSystem) t.typeSystem(); X10FieldInstance fi = (X10FieldInstance) n.fieldInstance(); X10FieldDef fd = fi.x10Def(); if (target instanceof TypeNode) { assert (fi.flags().isStatic()); TypeNode tn = (TypeNode) target; if (t instanceof ParameterType) { // Rewrite to the class declaring the field. target = tn.typeRef(fd.container()); n = (Field_c) n.target(target); } if (t.isClass()) { X10ClassType ct = (X10ClassType)t.toClass(); target = tn.typeRef(Types.ref(getStaticMemberContainer(ct.x10Def()))); } } String pat = getCppImplForDef(fd); if (pat != null) { Map<String,Object> components = new HashMap<String,Object>(); components.put("this", target); components.put("0", target); emitter.nativeSubst("Native", components, tr, pat, sw); return; } sw.begin(0); // TODO: capture constant fields as variables if (!n.flags().isStatic()) { X10CPPContext_c c = (X10CPPContext_c) tr.context(); if (target instanceof X10Special_c && ((X10Special_c)target).isSelf()) { assert (false) : ("Loki knows why we got here..."); //sw.write((context.Self() == null) ? "self" : context.Self()); //sw.write("->"); } } String name = n.name().id().toString(); assert (target != null); if (target instanceof Expr) { if (fi.flags().isStatic()) { sw.write("((void)"); n.printSubExpr((Expr) target, false, sw, tr); sw.write(","); sw.write(Emitter.translateType(target.type())); sw.write("::"); sw.allowBreak(2, 3, "", 0); sw.write(mangled_field_name(name+STATIC_FIELD_ACCESSOR_SUFFIX) + "()"); sw.write(")"); sw.end(); return; } else { boolean needsNullCheck = !Types.isX10Struct(t) && needsNullCheck(target); boolean assoc = !(target instanceof New_c || target instanceof Binary_c); if (needsNullCheck) sw.write("x10aux::nullCheck("); n.printSubExpr((Expr) target, assoc, sw, tr); if (needsNullCheck) sw.write(")"); } } else if (target instanceof TypeNode || target instanceof AmbReceiver) { n.print(target, sw, tr); } if (n.fieldInstance().flags().isStatic()) { sw.write("::"); } else { sw.write("->"); } sw.allowBreak(2, 3, "", 0); if (!n.fieldInstance().flags().isStatic()) { if (target instanceof X10Special_c && ((X10Special_c)target).kind().equals(X10Special_c.SUPER)) { sw.write(Emitter.translateType(context.currentClass().superClass())+"::"); } sw.write(mangled_field_name(name)); } else { sw.write(mangled_field_name(name+STATIC_FIELD_ACCESSOR_SUFFIX) + "()"); } sw.end(); } public void visit(Local_c n) { X10CPPContext_c c = (X10CPPContext_c) tr.context(); LocalInstance var = n.localInstance(); // Make sure there is no mismatch between n.name() and var.name() if (var.name() != n.name().id()) { assert var.name() == n.name().id(); } if (c.isInsideClosure()) c.saveEnvVariableInfo(var.name().toString(), var.lval()); sw.write(mangled_non_method_name(var.name().toString())); } public void visit(New_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = (TypeSystem)context.typeSystem(); ConstructorInstance constructor = n.constructorInstance(); boolean stackAllocate = false; boolean embed = false; // Danger Will Robinson! Give programmer plenty of rope to hang themselves!! // If there's a @StackAllocate annotation on a new expression, then do what // the programmer asked us to and stack allocate the storage for the object. // If the programmer was incorrect about the lifetime of the object, then // the program will almost certainly crash in some unexpected way. Type annotation = xts.StackAllocate(); if (!((X10Ext) n.ext()).annotationMatching(annotation).isEmpty()) { stackAllocate = true; // System.err.println("@StackAllocate " + n); } Type annotation2 = xts.Embed(); if (!((X10Ext) n.ext()).annotationMatching(annotation2).isEmpty()) { embed = true; // System.err.println("@StackAllocate " + n); } if (n.qualifier() != null) throw new InternalCompilerError("Qualified new not supported"); if (n.body() != null) throw new InternalCompilerError("Anonymous innner classes should have been removed."); if (stackAllocate) { sw.write(context.getStackAllocName()+"."+CONSTRUCTOR+"("); } else if (embed) { sw.write("&"+context.getEmbeddedFieldName()+";"); sw.newline(); sw.write(context.getEmbeddedFieldName()+"."+CONSTRUCTOR+"("); } else { sw.write(Emitter.translateType(n.objectType().type())+"::"+MAKE+"("); } sw.begin(0); for (Iterator<Expr> i = n.arguments().iterator(); i.hasNext(); ) { Expr e = i.next(); n.print(e, sw, tr); if (i.hasNext()) { sw.write(","); sw.allowBreak(0, " "); } } sw.write(")"); sw.end(); } public void visit(FloatLit_c n) { String val; if (n.kind() == FloatLit_c.FLOAT) val = Float.toString((float) n.value()) + "f"; else if (n.kind() == FloatLit_c.DOUBLE) val = Double.toString(n.value()); else throw new InternalCompilerError("Unrecognized FloatLit kind " + n.kind()); sw.write(val); } public void visit(IntLit_c n) { String val; switch (n.kind()) { case ULONG: if (n.boundary()) val = "0x" + Long.toHexString(n.value()).toUpperCase() + "llu"; else if (n.value() < 0) val = "0x" + Long.toHexString(n.value()).toUpperCase() + "llu"; else val = Long.toString(n.value()) + "ull"; break; case UINT: if (n.value() >= 0x80000000L) val = "0x" + Long.toHexString(n.value()).toUpperCase() + "u"; else if (n.boundary()) val = "0x" + Long.toHexString(-n.value()).toUpperCase() + "u"; else val = Long.toString((int) n.value()) + "u"; break; case LONG: if (n.boundary()) val = "0x" + Long.toHexString(n.value()).toUpperCase() + "llu"; else val = Long.toString(n.value()) + "ll"; break; case INT: if (n.value() >= 0x80000000L) val = "0x" + Long.toHexString(n.value()).toUpperCase() + "u"; else if (n.boundary()) val = "0x" + Long.toHexString(-n.value()).toUpperCase() + "u"; else val = Long.toString((int) n.value()); break; case BYTE: case SHORT: case UBYTE: case USHORT: val = Long.toString((int) n.value()); break; default: throw new InternalCompilerError("Unrecognized IntLit kind " + n.kind()); } sw.write("("); sw.begin(0); sw.write("(" + Emitter.translateType(n.type(), true) + ")"); sw.write(val); sw.end(); sw.write(")"); } public void visit(NullLit_c n) { sw.write("X10_NULL"); } public void visit(StringLit_c n) { TypeSystem xts = tr.typeSystem(); boolean nativeString = false; try { Type annotation = xts.systemResolver().findOne(QName.make("x10.compiler.NativeString")); if (!((X10Ext) n.ext()).annotationMatching(annotation).isEmpty()) { nativeString = true; // System.err.println("@NativeString " + n); } } catch (SemanticException e) { /* Ignore exception when looking for annotation */ } if (nativeString) { sw.write("\""); sw.write(StringUtil.escape(n.value())); sw.write("\""); } else { sw.write("x10aux::makeStringLit(\""); sw.write(StringUtil.escape(n.value())); sw.write("\")"); } } public void visit(CharLit_c lit) { sw.write("((x10_char)'"+StringUtil.escape(lit.value())+"')"); } public void visit(BooleanLit_c lit) { sw.write(lit.toString()); } public void visit(Id_c n) { sw.write(mangled_non_method_name(n.id().toString())); } public void visit(X10Cast_c c) { TypeNode tn = c.castType(); assert tn instanceof CanonicalTypeNode; switch (c.conversionType()) { case CHECKED: case PRIMITIVE: case SUBTYPE: case UNCHECKED: if (tn instanceof X10CanonicalTypeNode) { X10CanonicalTypeNode xtn = (X10CanonicalTypeNode) tn; Type t = Types.baseType(xtn.type()); Type f = Types.baseType(c.expr().type()); Type t_ = Types.stripConstraints(t); Type f_ = Types.stripConstraints(f); TypeSystem xts = tr.typeSystem(); Context context = (Context) tr.context(); if (xts.typeEquals(f_, t_, context)) { if (c.expr() instanceof NullLit_c) { // Could still need a C++ level cast to make the typing work // FIXME: if we make X10_NULL a void*, we wouldn't need this cast, // but need to verify if all the template overloading in basic_functions // would still work. sw.write("reinterpret_cast"); sw.write(chevrons(Emitter.translateType(t_, true)) + "("); c.printSubExpr(c.expr(), true, sw, tr); sw.write(")"); } else { c.printSubExpr(c.expr(), true, sw, tr); } } else if (c.conversionType()==Converter.ConversionType.SUBTYPE && xts.isSubtype(f_, t_, context)) { // If it is an upcast, we can implement as a class_cast_unchecked. // However we still need to do something for two reasons // (a) if it is a struct, then the upcast will autobox // (b) if it is not a struct, we might still need the cast to // get the right C++ types so that overload resolution will work. sw.write(selectUncheckedCast(xts, f_, t_)); sw.write(chevrons(Emitter.translateType(t_, true)) + "("); c.printSubExpr(c.expr(), true, sw, tr); sw.write(")"); } else { if (c.conversionType()==Converter.ConversionType.UNCHECKED) { sw.write(selectUncheckedCast(xts, f_, t_)); } else { sw.write("x10aux::class_cast"); } sw.write(chevrons(Emitter.translateType(t_, true)) + "("); c.printSubExpr(c.expr(), true, sw, tr); sw.write(")"); } } else { throw new InternalCompilerError("Ambiguous TypeNode survived type-checking.", tn.position()); } break; case UNBOXING: throw new InternalCompilerError("Unknown conversion type after type-checking.", c.position()); case UNKNOWN_IMPLICIT_CONVERSION: throw new InternalCompilerError("Unknown conversion type after type-checking.", c.position()); case UNKNOWN_CONVERSION: throw new InternalCompilerError("Unknown conversion type after type-checking.", c.position()); case BOXING: throw new InternalCompilerError("Boxing conversion should have been rewritten.", c.position()); } } private String selectUncheckedCast(TypeSystem xts, Type fromType, Type toType) { if (xts.isObjectOrInterfaceType(fromType, tr.context()) && xts.isObjectOrInterfaceType(toType, tr.context())) { return "reinterpret_cast"; } else { return "x10aux::class_cast_unchecked"; } } public void visit(SubtypeTest_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (n.equals()) { sw.write("x10aux::sametype"); sw.write(chevrons( Emitter.translateType(n.subtype().type(), true) + "," + Emitter.translateType(n.supertype().type(), true) )); } else { sw.write("x10aux::subtypeof"); sw.write(chevrons( Emitter.translateType(n.subtype().type(), true) + "," + Emitter.translateType(n.supertype().type(), true) )); } sw.write("()"); } public void visit(HasZeroTest_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); sw.write("x10aux::haszero"); sw.write(chevrons( Emitter.translateType(n.parameter().type(), true) )); sw.write("()"); } public void visit(X10Instanceof_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); sw.write("x10aux::instanceof"); sw.write(chevrons(Emitter.translateType(n.compareType().type(), true))); sw.write("("); sw.begin(0); n.printSubExpr(n.expr(), false, sw, tr); sw.end(); sw.write(")"); } public void visit(Throw_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); sw.write("x10aux::throwException(x10aux::nullCheck("); n.print(n.expr(), sw, tr); sw.write("));"); } public void visit(Try_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); TypeSystem xts = tr.typeSystem(); X10Ext_c ext = (X10Ext_c) n.ext(); if (ext.initVals != null) { Set<LocalDef> asyncInits = context.findData(SharedVarsMethods.ASYNC_INIT_VALS_KEY); if (asyncInits == null) { asyncInits = CollectionFactory.newHashSet(ext.initVals); context.addData(SharedVarsMethods.ASYNC_INIT_VALS_KEY, asyncInits); } else { asyncInits.addAll(ext.initVals); } } sw.write("try"); assert (n.tryBlock() instanceof Block_c); n.printSubStmt(n.tryBlock(), sw, tr); sw.newline(0); // C++ does dispatching based on the static type of the thrown exception. // X10, like Java needs to dispatch on the dynamic type of the thrown exception. // So, we have to do the dispatching ourselves. sw.newline(); String excVar = "__exc" + getUniqueId_(); sw.write("catch ("+ Emitter.translateType(xts.CheckedThrowable(), true)+" " + excVar + ") {"); sw.newline(4); sw.begin(0); if (n.catchBlocks().size() > 0) { context.setExceptionVar(excVar); for (Catch cb : n.catchBlocks()) { sw.newline(0); n.printBlock(cb, sw, tr); } } sw.newline(); sw.write("throw;"); sw.end(); sw.newline(); sw.write("}"); } public void visit(Catch_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); String excVar = context.getExceptionVar(); sw.newline(); sw.write("if ("); String type = Emitter.translateType(n.formal().type().type(), true); if (n.formal().type().type().typeEquals(tr.typeSystem().CheckedThrowable(), context)) { sw.write("true"); } else { sw.write("x10aux::instanceof" + chevrons(type) + "(" + excVar + ")"); } sw.write(") {"); sw.newline(4); sw.begin(0); n.printBlock(n.formal(), sw, tr); sw.write(" ="); sw.allowBreak(2, " "); sw.write("static_cast" + chevrons(type) + "(" + excVar + ");"); sw.newline(0); n.print(n.body(), sw, tr); sw.end(); sw.newline(); sw.write("} else"); } public void visit(ParExpr_c n) { n.print(n.expr(), sw, tr); } public void visit(Conditional_c n) { n.printSubExpr(n.cond(), false, sw, tr); sw.unifiedBreak(2); sw.write("? ("); sw.begin(0); n.printSubExpr(n.consequent(), true, sw, tr); sw.end(); sw.write(")"); sw.unifiedBreak(2); sw.write(": ("); sw.begin(0); n.printSubExpr(n.alternative(), true, sw, tr); sw.end(); sw.write(")"); } public void visit(X10Special_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); if (context.isInsideClosure()) { assert n.kind().equals(X10Special_c.THIS) || n.kind().equals(X10Special_c.SUPER); sw.write(SAVED_THIS); context.saveEnvVariableInfo(THIS); } else { assert n.kind().equals(X10Special_c.THIS) || n.kind().equals(X10Special_c.SUPER) : "Should be this or super"; if (Types.isX10Struct(n.type())) { sw.write("(*this)"); } else { sw.write("this"); } } } public static String getClosureName(String className, int id) { // TODO: factor out into a constant return className+"__closure__"+id; } private boolean envContainsVar(List<VarInstance<? extends VarDef>> env, VarInstance<? extends VarDef> vi) { for (VarInstance<? extends VarDef> e : env) { if (e.def() == vi.def()) return true; } return false; } public void visit(Closure_c n) { X10CPPContext_c c = (X10CPPContext_c) tr.context(); emitter.enterClosure(c); ClosureDef closureDef = n.closureDef(); CodeInstance<?> ci = closureDef.methodContainer().get(); X10ClassType hostClassType = (X10ClassType) closureDef.typeContainer().get(); X10ClassDef hostClassDef = hostClassType.x10Def(); TypeSystem xts = tr.typeSystem(); List<Type> freeTypeParams = new ArrayList<Type>(); while (ci instanceof ClosureInstance) ci = ((ClosureDef) ci.def()).methodContainer().get(); if (ci instanceof MethodInstance) { MethodInstance xmi = (MethodInstance) ci; // in X10, static methods do not inherit the template params of their classes if (!xmi.flags().isStatic()) freeTypeParams.addAll(hostClassDef.typeParameters()); freeTypeParams.addAll(xmi.typeParameters()); } else if (ci instanceof InitializerInstance) { InitializerInstance ii = (InitializerInstance) ci; if (!ii.def().flags().isStatic()) freeTypeParams.addAll(hostClassDef.typeParameters()); } else { // could be a constructor or other non-static thing freeTypeParams.addAll(hostClassDef.typeParameters()); } String hostClassName = translate_mangled_FQN(Emitter.fullName(hostClassType).toString(), "_"); c.setInsideClosure(true); int id = getConstructorId(c); String cname = getClosureName(hostClassName, id); boolean in_template_closure = false; StringBuffer cnamet_ = new StringBuffer(cname); String prefix = "<"; for (Type t : freeTypeParams) { in_template_closure = true; cnamet_.append(prefix + Emitter.translateType(t)); prefix = ","; } if (in_template_closure) cnamet_.append(" >"); String cnamet = cnamet_.toString(); // Prepend this stream to closures. Closures are created from the outside in. // Thus, later closures can be used by earlier ones, but not vice versa. ClassifiedStream saved_closures = c.closures; ClassifiedStream saved_generic_closures = c.genericFunctionClosures; c.closures = sw.getNewStream(c.closures.ext, c.closures, true); sw.pushCurrentStream(c.closures); // A stream to put definitions of static variables for the closure class. // If the def is not templatized, it has to go in the CC stream independent of // which stream the rest of the closure declaration is going. ClassifiedStream defn_s = in_template_closure ? sw.currentStream() : c.staticClosureDefinitions; String headerGuard = getHeaderGuard(cname); sw.write("#ifndef "+headerGuard+"_CLOSURE"); sw.newline(); sw.write("#define "+headerGuard+"_CLOSURE"); sw.newline(); Type retType = n.returnType().type(); X10ClassType sup = (X10ClassType) ClosureSynthesizer.closureBaseInterfaceDef(xts,0, n.formals().size(), retType.isVoid()).asType(); List<Type> supArgs = new ArrayList<Type>(); for (Formal formal : n.formals()) supArgs.add(formal.type().typeRef().get()); if (!retType.isVoid()) supArgs.add(retType); String superType = Emitter.translateType(sup.typeArguments(supArgs)); String superTypeRef = Emitter.translateType(sup.typeArguments(supArgs), true); sw.write("#include <x10/lang/Closure.h>"); sw.newline(); String header = getHeader(sup); sw.write("#include <"+header+">"); sw.newline(); // class header if (!freeTypeParams.isEmpty()) emitter.printTemplateSignature(freeTypeParams, sw); sw.write("class "+cname+" : public "+CLOSURE_TYPE+" {"); sw.newline(4); sw.begin(0); sw.write("public:") ; sw.newline(); sw.forceNewline(); /* ITables declarations */ sw.write("static "+(in_template_closure ? "typename " : "")+superType+(in_template_closure ? "::template itable " : "::itable")+chevrons(cnamet)+" _itable;"); sw.newline(); sw.write("static x10aux::itable_entry _itables[2];"); sw.newline(); sw.forceNewline(); sw.write("virtual x10aux::itable_entry* _getITables() { return _itables; }"); sw.newline(); sw.forceNewline(); sw.write("// closure body"); sw.newline(); sw.write(Emitter.translateType(retType, true)+" "+Emitter.mangled_method_name(ClosureCall.APPLY.toString())+"("); prefix = ""; for (Formal formal : n.formals()) { sw.write(prefix); n.print(formal, sw, tr); prefix = ", "; } sw.write(") "); n.print(n.body(), sw, tr); sw.newline(); sw.forceNewline(); sw.write("// captured environment"); sw.newline(); List<VarInstance<?>> refs = computeBoxedRefs(c, closureDef); List<VarInstance<? extends VarDef>> env = closureDef.capturedEnvironment(); for (VarInstance<?> vi : c.variables) { if (!envContainsVar(env, vi) && !vi.name().toString().equals(THIS)) { // Sanity check String msg = "Closure "+n+" at "+n.position()+" captures "+vi+" which is not in the environment"; Warnings.issue(tr.job(), msg, n.position()); } } List<VarInstance<? extends VarDef>> prunned = new ArrayList<VarInstance<? extends VarDef>>(env.size()); for (VarInstance<?> vi : env) { VarDef def = vi.def(); if ((def instanceof X10LocalDef) || def instanceof ThisDef) { prunned.add(vi); } } env = prunned; if (((X10CPPCompilerOptions)tr.job().extensionInfo().getOptions()).x10_config.DEBUG && !in_template_closure) { String key = ((StreamWrapper)sw).getStreamName(StreamWrapper.CC); Map<String, LineNumberMap> fileToLineNumberMap = c.<Map<String, LineNumberMap>>findData(X10CPPTranslator.FILE_TO_LINE_NUMBER_MAP); if (fileToLineNumberMap != null) { final LineNumberMap lineNumberMap = fileToLineNumberMap.get(key); if (lineNumberMap != null) { int numMembers = env.size(); for (int i = 0; i < numMembers; i++) { VarInstance<?> var = env.get(i); String name = var.name().toString(); if (name.equals(THIS)) name = SAVED_THIS; lineNumberMap.addClosureMember(name, var.type().toString(), cname, cnamet_.toString(), c.currentCode().position().file(), c.currentCode().position().line(), c.currentCode().position().endLine()); } if (numMembers > 0) { for (int i=0; i< n.formals().size(); i++) { Formal f = n.formals().get(i); X10ClassType t = f.type().type().toClass(); lineNumberMap.addLocalVariableMapping(f.name().toString(), f.type().toString(), c.currentCode().position().line(), c.currentCode().position().endLine(), c.currentCode().position().file(), true, -2, (t==null?false:t.isX10Struct())); } } } } } emitter.printDeclarationList(sw, c, env, refs); sw.forceNewline(); sw.write("x10aux::serialization_id_t "+SERIALIZE_ID_METHOD+"() {"); sw.newline(4); sw.begin(0); sw.write("return "+SERIALIZATION_ID_FIELD+";"); sw.end(); sw.newline(); sw.write("}"); sw.newline(); sw.forceNewline(); generateClosureSerializationFunctions(c, cnamet, sw, n.body(), env, refs); sw.write(cname+"("); for (int i = 0; i < env.size(); i++) { if (i > 0) sw.write(", "); VarInstance<?> var = (VarInstance<?>) env.get(i); String name = var.name().toString(); if (name.equals(THIS)) name = SAVED_THIS; else name = mangled_non_method_name(name); if (refs.contains(var)) { sw.write(make_captured_lval(var.type()) + " " + name); } else { sw.write(Emitter.translateType(var.type(), true) + " " + name); } } sw.write(")"); sw.begin(0); // FIXME: factor out this loop for (int i = 0 ; i < env.size() ; i++) { VarInstance<?> var = (VarInstance<?>) env.get(i); String name = var.name().toString(); if (name.equals(THIS)) name = SAVED_THIS; else name = mangled_non_method_name(name); if (i > 0) sw.write(", "); else sw.write(" : "); sw.write(name + "(" + name + ")"); } sw.end(); sw.write(" { }"); sw.newline(); sw.forceNewline(); sw.write("static const x10aux::serialization_id_t "+SERIALIZATION_ID_FIELD+";"); sw.newline(); sw.forceNewline(); sw.write("static const x10aux::RuntimeType* getRTT() {"+ " return x10aux::getRTT"+chevrons(superType)+"(); }"); sw.newline(); sw.write("virtual const x10aux::RuntimeType *_type() const {"+ " return x10aux::getRTT"+chevrons(superType)+"(); }"); sw.newline(); sw.forceNewline(); sw.write(Emitter.translateType(xts.String(), true)+" toString() {"); sw.newline(4); sw.begin(0); sw.write("return x10aux::makeStringLit(this->toNativeString());"); sw.end(); sw.newline(); sw.write("}"); sw.newline(); sw.forceNewline(); sw.write("const char* toNativeString() {"); sw.newline(4); sw.begin(0); sw.write("return \""+StringUtil.escape(n.position().nameAndLineString())+"\";"); sw.end(); sw.newline(); sw.write("}"); sw.end(); sw.newline(); sw.forceNewline(); sw.write("};"); sw.newline(); sw.forceNewline(); if (in_template_closure) emitter.printTemplateSignature(freeTypeParams, defn_s); // TODO: To workaround XTENLANG-467, we are explicitly qualifying inherited member functions here. // This is less than ideal, since it can introduce subtle bugs when the C++ code is refactored // (an overridden member function will not be called from the itable, which is very non-intuitive). // As soon as XTENLANG-467 is fixed, take out the explicit qualifications and let C++ member lookup do its job... defn_s.writeln((in_template_closure ? "typename ": "")+superType+(in_template_closure ? "::template itable ": "::itable")+chevrons(cnamet)+ cnamet+"::_itable(&"+REFERENCE_TYPE+"::equals, &"+CLOSURE_TYPE+"::hashCode, &"+ cnamet+"::"+Emitter.mangled_method_name(ClosureCall.APPLY.toString())+", &"+ cnamet+"::toString, &"+CLOSURE_TYPE+"::typeName);"); if (in_template_closure) emitter.printTemplateSignature(freeTypeParams, defn_s); defn_s.write("x10aux::itable_entry "+cnamet+"::_itables[2] = {"); defn_s.write("x10aux::itable_entry(&x10aux::getRTT"+chevrons(superType)+", &"+cnamet+"::_itable),"); defn_s.write("x10aux::itable_entry(NULL, NULL)};"); defn_s.newline(); defn_s.forceNewline(); int kind = 0; try { if (!((X10Ext)(n.body()).ext()).annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.AsyncClosure"))).isEmpty()) { kind = 1; } if (!((X10Ext)(n).ext()).annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.AsyncClosure"))).isEmpty()) { kind = 1; } } catch (SemanticException e) { } try { if (!((X10Ext)(n.body()).ext()).annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.RemoteInvocation"))).isEmpty()) { kind = 2; } if (!((X10Ext)(n).ext()).annotationMatching(xts.systemResolver().findOne(QName.make("x10.compiler.RemoteInvocation"))).isEmpty()) { kind = 2; } } catch (SemanticException e) { } generateClosureDeserializationIdDef(defn_s, cnamet, freeTypeParams, hostClassName, n.body(), kind); sw.write("#endif // "+headerGuard+"_CLOSURE"); sw.newline(); // Done generating closure definition. Pop streams. sw.popCurrentStream(); c.closures = saved_closures; c.genericFunctionClosures = saved_generic_closures; // create closure instantiation. // note that we alloc using the typeof the superType but we pass in the correct size // this is because otherwise alloc may (when debugging is on) try to examine the // RTT of the closure (which doesn't exist) // first get the template arguments (if any) prefix="<"; StringBuffer sb = new StringBuffer(); for (Type t : freeTypeParams) { sb.append(prefix+Emitter.translateType(t, true)); prefix = ","; } if (prefix.equals(",")) sb.append(">"); String templateArgs = sb.toString(); boolean stackAllocateClosure = ((X10CPPContext_c)c).closureOuter.stackAllocateClosure; if (!stackAllocateClosure) { sw.write("reinterpret_cast"+chevrons(make_ref(superType))+"("); sw.write("(new (x10aux::alloc"+chevrons(superType)+"(sizeof("+cname+templateArgs+")))"); } sw.write(cname+templateArgs+"("); for (int i = 0; i < env.size(); i++) { if (i > 0) sw.write(", "); VarInstance<?> var = (VarInstance<?>) env.get(i); String name = var.name().toString(); if (name.equals(THIS)) { // FIXME: Hack upon hack... if (((X10CPPContext_c)c.pop()).isInsideClosure()) { name = SAVED_THIS; } else if (xts.isStruct(var.type())) { name = STRUCT_THIS; } } else { name = mangled_non_method_name(name); } if (refs.contains(var)) { sw.write("&("+name+")"); } else { sw.write(name); } } sw.write(")"); if (!stackAllocateClosure) { sw.write("))"); } c.finalizeClosureInstance(); emitter.exitClosure(c); } protected List<VarInstance<?>> computeBoxedRefs(X10CPPContext_c c, ClosureDef closureDef) { List<Type> ats = closureDef.annotationsNamed(QName.make("x10.compiler.Ref")); List<VarInstance<?>> refs = new ArrayList<VarInstance<?>>(); for (Type at : ats) { Expr exp = ((X10ParsedClassType_c) at).propertyInitializer(0); if (exp instanceof X10Local_c) { refs.add(((X10Local_c) exp).varInstance()); } } for (VarInstance<?> var : closureDef.capturedEnvironment()) { VarDef def = var.def(); if ((def instanceof X10LocalDef)) { X10LocalDef ld = ((X10LocalDef)def); if (!ld.flags().isFinal() || var.lval()) { refs.add(var); } } } return refs; } protected void generateClosureSerializationFunctions(X10CPPContext_c c, String cnamet, StreamWrapper inc, Block block, List<VarInstance<?>> env, List<VarInstance<?>> refs) { inc.write("void "+SERIALIZE_BODY_METHOD+"("+SERIALIZATION_BUFFER+" &buf) {"); inc.newline(4); inc.begin(0); // FIXME: factor out this loop for (int i = 0; i < env.size(); i++) { if (i > 0) inc.newline(); VarInstance<?> var = (VarInstance<?>) env.get(i); String name = var.name().toString(); if (name.equals(THIS)) { name = SAVED_THIS; } else { name = mangled_non_method_name(name); } inc.write("buf.write(this->" + name + ");"); } inc.end(); inc.newline(); inc.write("}"); inc.newline(); inc.forceNewline(); inc.write("template<class __T> static "+make_ref("__T")+" "+DESERIALIZE_METHOD+"("+DESERIALIZATION_BUFFER+" &buf) {"); inc.newline(4); inc.begin(0); inc.writeln(cnamet+"* storage = x10aux::alloc"+chevrons(cnamet)+"();"); inc.writeln("buf.record_reference(storage);"); // FIXME: factor out this loop for (int i = 0; i < env.size(); i++) { VarInstance<?> var = (VarInstance<?>) env.get(i); Type t = var.type(); String type; if (refs.contains(var)) { type = make_captured_lval(t); } else { type = Emitter.translateType(t, true); } String name = var.name().toString(); if (name.equals(THIS)) { name = SAVED_THIS; } else { name = mangled_non_method_name(name); } inc.write(type + " that_"+name+" = buf.read"+chevrons(type)+"();"); inc.newline(); } inc.write(make_ref(cnamet)+" this_ = new (storage) "+cnamet+"("); // FIXME: factor out this loop for (int i = 0; i < env.size(); i++) { VarInstance<?> var = (VarInstance<?>) env.get(i); String name = var.name().toString(); if (name.equals(THIS)) name = SAVED_THIS; else name = mangled_non_method_name(name); if (i > 0) inc.write(", "); inc.write("that_"+name); } inc.write(");"); inc.newline(); inc.write("return this_;"); inc.end(); inc.newline(); inc.write("}"); inc.newline(); inc.forceNewline(); } protected String closure_kind_strs[] = new String[] { "x10aux::CLOSURE_KIND_NOT_ASYNC", "x10aux::CLOSURE_KIND_SIMPLE_ASYNC", "x10aux::CLOSURE_KIND_GENERAL_ASYNC" }; protected void generateClosureDeserializationIdDef(ClassifiedStream defn_s, String cnamet, List<Type> freeTypeParams, String hostClassName, Block block, int kind) { TypeSystem xts = tr.typeSystem(); boolean in_template_closure = freeTypeParams.size()>0; if (in_template_closure) emitter.printTemplateSignature(freeTypeParams, defn_s); defn_s.write("const x10aux::serialization_id_t "+cnamet+"::"+SERIALIZATION_ID_FIELD+" = "); defn_s.newline(4); String template = in_template_closure ? "template " : ""; defn_s.write("x10aux::DeserializationDispatcher::addDeserializer("+ cnamet+"::"+template+DESERIALIZE_METHOD+ chevrons("x10::lang::Reference")+","+closure_kind_strs[kind]+");"); defn_s.newline(); defn_s.forceNewline(); } private Closure_c getClosureLiteral(Expr target) { if (target instanceof Closure_c) return (Closure_c) target; if (target instanceof ParExpr_c) return getClosureLiteral(((ParExpr_c)target).expr()); return null; } // ClosureCall_c really means "call operator() on me, and if I happen to be a closure literal understand that means invoking my body" // So we have to handle 3 different cases: // (a) closure literal that for some odd reason wasn't inlined (should not really happen...) // (b) a function type // (c) an class (anonymous or not) that has an operator() public void visit(ClosureCall_c c) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); Expr target = c.target(); Type t = target.type(); boolean needsNullCheck = needsNullCheck(target); Closure_c lit = getClosureLiteral(target); if (lit != null) { // Optimize to stack-allocated closure and non-virtual dispatch context.setStackAllocateClosure(true); c.printSubExpr(target, sw, tr); context.setStackAllocateClosure(false); sw.write("."+Emitter.mangled_method_name(ClosureCall.APPLY.toString())+"("); } else { if (t.isClass() && t.toClass().isAnonymous()) { ClassType tc = t.toClass(); if (tc.interfaces().size() > 0) { t = tc.interfaces().get(0); } else { t = tc.superClass(); } } if (t.isClass() && t.toClass().flags().isInterface()) { MethodInstance ami = null; TypeSystem xts = tr.typeSystem(); try { List<Type> actualTypes = new ArrayList<Type>(); for (Expr a : c.arguments()) { actualTypes.add(a.type()); } ami = xts.findMethod(t, xts.MethodMatcher(c.type(), ClosureCall.APPLY, actualTypes, context)); // todo: double check this code } catch (SemanticException e) { e.printStackTrace(); assert (false); } invokeInterface(c, target, c.arguments(), make_ref(REFERENCE_TYPE), t.toClass(), ami, needsNullCheck); return; } else { if (needsNullCheck) sw.write("x10aux::nullCheck("); c.printSubExpr(target, sw, tr); if (needsNullCheck) sw.write(")"); sw.write("->"+Emitter.mangled_method_name(ClosureCall.APPLY.toString())+"("); } } sw.begin(0); boolean first = true; for (Expr e : c.arguments()) { if (!first) { sw.write(","); sw.allowBreak(0, " "); } c.print(e, sw, tr); first = false; } sw.end(); sw.write(")"); } public void visit(X10CanonicalTypeNode_c n) { Type t = n.type(); if (t == null) throw new InternalCompilerError("Unknown type"); sw.write(Emitter.translateType(t)); } public void visit(X10Unary_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); Expr left = n.expr(); Type l = left.type(); TypeSystem xts = (TypeSystem) tr.typeSystem(); NodeFactory nf = tr.nodeFactory(); Unary.Operator op = n.operator(); if (op == Unary.POST_DEC || op == Unary.POST_INC || op == Unary.PRE_DEC || op == Unary.PRE_INC) { // TODO visit((Unary_c)n); return; } if (l.isNumeric()) { // TODO: get rid of this special case by defining native operators visit((Unary_c)n); return; } if (l.isBoolean()) { // TODO: get rid of this special case by defining native operators visit((Unary_c)n); return; } assert (false) : ("User-defined unary operators should have been desugared earier"); // FIXME: move this to the Desugarer Name methodName = X10Unary_c.unaryMethodName(op); Expr receiver = left; if (methodName == null) throw new InternalCompilerError("No method to implement " + n, n.position()); try { List<Type> types = Arrays.asList(new Type[] { }); MethodInstance mi = xts.findMethod(receiver.type(), xts.MethodMatcher(receiver.type(), methodName, types, context)); List<Expr> args = Arrays.asList(new Expr[] { }); n.print(nf.Call(n.position(), receiver, nf.Id(n.position(), methodName), args).methodInstance(mi).type(mi.returnType()), sw, tr); } catch (SemanticException e) { } } public void visit(Unary_c n) { Unary_c.Operator operator = n.operator(); Expr expr = n.expr(); if (operator == Unary_c.NEG && expr instanceof IntLit) { IntLit_c lit = (IntLit_c) expr; IntLit.Kind kind = lit.kind().toSigned(); n.printSubExpr(lit.value(-lit.longValue()).kind(kind), true, sw, tr); } else if (operator.isPrefix()) { sw.write(operator.toString()); n.printSubExpr(expr, false, sw, tr); } else { n.printSubExpr(expr, false, sw, tr); sw.write(operator.toString()); } } public void visit(X10Binary_c n) { X10CPPContext_c context = (X10CPPContext_c) tr.context(); Expr left = n.left(); Type l = left.type(); Expr right = n.right(); Type r = right.type(); TypeSystem xts = (TypeSystem) tr.typeSystem(); NodeFactory nf = tr.nodeFactory(); Binary.Operator op = n.operator(); if (op == Binary.EQ || op == Binary.NE) { // FIXME: get rid of this special case sw.write("("); sw.begin(0); if (op == Binary.NE) { sw.write("!"); } sw.write(STRUCT_EQUALS+"("); sw.begin(0); n.printSubExpr(left, sw, tr); sw.write(","); sw.allowBreak(0, " "); n.printSubExpr(right, sw, tr); sw.end(); sw.write(")"); sw.end(); sw.write(")"); return; } if (l.isNumeric() && r.isNumeric()) { // TODO: get rid of this special case by defining native operators visit((Binary_c)n); return; } if (l.isBoolean() && r.isBoolean()) { // TODO: get rid of this special case by defining native operators visit((Binary_c)n); return; } if (op == Binary.ADD && (l.isSubtype(xts.String(), context) || r.isSubtype(xts.String(), context))) { // TODO: get rid of this special case by defining native operators visit((Binary_c)n); return; } assert (false) : ("User-defined binary operators should have been desugared earier"); // FIXME: move this to the Desugarer boolean inv = n.invert(); Name methodName = inv ? X10Binary_c.invBinaryMethodName(op) : X10Binary_c.binaryMethodName(op); Expr receiver = inv ? right : left; Expr arg = inv ? left : right; if (methodName == null) throw new InternalCompilerError("No method to implement " + n, n.position()); try { List<Type> types = Arrays.asList(new Type[] { arg.type() }); MethodInstance mi = xts.findMethod(receiver.type(), xts.MethodMatcher(receiver.type(), methodName, types, context)); List<Expr> args = Arrays.asList(new Expr[] { arg }); n.print(nf.Call(n.position(), receiver, nf.Id(n.position(), methodName), args).methodInstance(mi).type(mi.returnType()), sw, tr); } catch (SemanticException e) { } } public void visit(Binary_c n) { String opString = n.operator().toString(); // Boolean short-circuiting operators are ok TypeSystem xts = tr.typeSystem(); assert (opString.equals("&&") || opString.equals("||")) : "visiting "+n.getClass()+" at "+n.position()+": "+n; n.printSubExpr(n.left(), true, sw, tr); sw.write(" "); sw.write(opString); sw.allowBreak(0, " "); n.printSubExpr(n.right(), false, sw, tr); } // allow overriding in subclasses (i.e. CUDACodeGenerator) // [DC] FIXME: ASTQuery.getCppRepParam still uses CPP_NATIVE_STRING directly protected String[] getCurrentNativeStrings() { return new String[] {CPP_NATIVE_STRING}; } String getCppImplForDef(X10Def o) { return getCppImplForDef(o, null); } String getCppImplForDef(X10Def o, String[] langbox) { TypeSystem xts = (TypeSystem) o.typeSystem(); Type annotation = xts.NativeType(); String[] our_langs = getCurrentNativeStrings(); for (String our_lang : our_langs) { List<Type> as = o.annotationsMatching(annotation); for (Type at : as) { assertNumberOfInitializers(at, 2); String lang = getStringPropertyInit(at, 0); if (lang != null && lang.equals(our_lang)) { String lit = getStringPropertyInit(at, 1); if (langbox!=null) langbox[0] = our_lang; return lit; } } } return null; } private String getCppImplForStmt(Stmt n) { TypeSystem xts = (TypeSystem) tr.typeSystem(); if (n.ext() instanceof X10Ext) { X10Ext ext = (X10Ext) n.ext(); Type annotation = xts.NativeType(); List<X10ClassType> as = ext.annotationMatching(annotation); String[] our_langs = getCurrentNativeStrings(); for (String our_lang : our_langs) { for (Type at : as) { assertNumberOfInitializers(at, 2); String lang = getStringPropertyInit(at, 0); if (lang != null && lang.equals(our_lang)) { String lit = getStringPropertyInit(at, 1); return lit; } } } } return null; } // FIXME: generic native methods will break void emitNativeAnnotation(String pat, List<ParameterType> typeParams, List<Type> typeArgs, Object receiver, List<String> params, List<? extends Object> args, List<ParameterType> typeParams2, List<Type> typeArgs2) { assert (receiver != null); //Object[] components = new Object[1+3*types.size() + args.size() + 3*typeArguments.size()]; Map<String,Object> components = new HashMap<String,Object>(); components.put("this", receiver); components.put("0", receiver); // [DC] these ought to still work, but there may now be a better solution if (receiver instanceof X10Special_c && ((X10Special_c)receiver).kind() == X10Special_c.SUPER) { pat = pat.replaceAll("\\(#0\\)->", Emitter.translateType(tr.context().currentClass().superClass())+"::"); // FIXME: HACK pat = pat.replaceAll("\\(#0\\)", "("+Emitter.translateType(((X10Special_c)receiver).type(), true)+"((#0*)this))"); // FIXME: An even bigger HACK (remove when @Native migrates to the body) pat = pat.replaceAll("\\(#this\\)->", Emitter.translateType(tr.context().currentClass().superClass())+"::"); // FIXME: HACK pat = pat.replaceAll("\\(#this\\)", "("+Emitter.translateType(((X10Special_c)receiver).type(), true)+"((#0*)this))"); // FIXME: An even bigger HACK (remove when @Native migrates to the body) } int i = 1; Iterator<ParameterType> typeParams_ = typeParams.iterator(); for (Type at : typeArgs) { components.put(typeParams_.next().name().toString(), at); components.put(Integer.toString(i++), at); components.put(Integer.toString(i++), "/"+"*"+" UNUSED "+"*"+"/"); components.put(Integer.toString(i++), "/"+"*"+" UNUSED "+"*"+"/"); } int j=0; Iterator<String> params_ = params.iterator(); for (Object e : args) { components.put(params_.next(), e); components.put(Integer.toString(i++), e); } Iterator<ParameterType> typeParams2_ = typeParams2.iterator(); for (Type at : typeArgs2) { components.put(typeParams2_.next().name().toString(), at); components.put(Integer.toString(i++), at); components.put(Integer.toString(i++), "/"+"*"+" UNUSED "+"*"+"/"); components.put(Integer.toString(i++), "/"+"*"+" UNUSED "+"*"+"/"); } emitter.nativeSubst("Native", components, tr, pat, sw); } private static boolean isPODType(Type t) { return (t.isBoolean() || t.isByte() || t.isShort() || t.isInt() || t.isLong() || t.isFloat() || t.isDouble()); } public void visit(Tuple_c c) { TypeSystem xts = tr.typeSystem(); Context context = tr.context(); // Handles Array initializer. Type T = Types.getParameterType(c.type(), 0); String type = Emitter.translateType(c.type()); String tmp = getId(); // [DC] this cast is needed to ensure everything has a ref type // otherwise overloads don't seem to work properly sw.write("("+make_ref(type)+")"); sw.write("(__extension__ ({"); sw.newline(4); sw.begin(0); sw.write(make_ref(type)+" "+tmp+"("); sw.write("x10::array::Array"+chevrons(Emitter.translateType(T, true))); sw.writeln("::_make("+c.arguments().size()+"));"); int count = 0; for (Expr e : c.arguments()) { sw.write(tmp+"->"+Emitter.mangled_method_name(SettableAssign.SET.toString())+"("); sw.writeln((count++)+", "); c.printSubExpr(e, false, sw, tr); sw.writeln(");"); } sw.write(tmp); X10CPPCompilerOptions opts = (X10CPPCompilerOptions) tr.job().extensionInfo().getOptions(); sw.write(";"); sw.end(); sw.newline(); sw.write("}))"); } } // end of MessagePassingCodeGenerator // vim:tabstop=4:shiftwidth=4:expandtab