/* * 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 x10c.visit; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicBoolean; import polyglot.ast.Assign; import polyglot.ast.Binary; import polyglot.ast.Binary.Operator; import polyglot.ast.Block; import polyglot.ast.BooleanLit; import polyglot.ast.Call; import polyglot.ast.Cast; import polyglot.ast.Catch; import polyglot.ast.CharLit; import polyglot.ast.ClassBody; import polyglot.ast.ClassDecl_c; import polyglot.ast.ClassMember; import polyglot.ast.Conditional; import polyglot.ast.ConstructorDecl; import polyglot.ast.Expr; import polyglot.ast.Field; import polyglot.ast.FieldDecl; import polyglot.ast.FlagsNode; import polyglot.ast.FloatLit; import polyglot.ast.Formal; import polyglot.ast.Id; import polyglot.ast.Initializer; import polyglot.ast.IntLit; import polyglot.ast.IntLit_c; import polyglot.ast.Local; import polyglot.ast.LocalDecl; import polyglot.ast.MethodDecl; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.NullLit; import polyglot.ast.ProcedureDecl; import polyglot.ast.Receiver; import polyglot.ast.Return; import polyglot.ast.Stmt; import polyglot.ast.StringLit; import polyglot.ast.Try; import polyglot.ast.TypeNode; import polyglot.ast.Unary; import polyglot.frontend.Job; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.ConstructorDef; import polyglot.types.ConstructorInstance; import polyglot.types.ContainerType; import polyglot.types.Context; import polyglot.types.FieldDef; import polyglot.types.FieldInstance; import polyglot.types.Flags; import polyglot.types.InitializerDef; import polyglot.types.LocalDef; import polyglot.types.LocalInstance; import polyglot.types.MethodDef; import polyglot.types.QName; import polyglot.types.Name; import polyglot.types.ObjectType; import polyglot.types.Package; import polyglot.types.ParsedClassType; 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.util.Pair; import polyglot.util.Position; import x10.types.X10FieldInstance; import x10.util.CollectionFactory; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import x10.X10CompilerOptions; import x10.ast.Closure; import x10.ast.ClosureCall; import x10.ast.ParExpr; import x10.ast.TypeParamNode; import x10.ast.X10Call; import x10.ast.X10Call_c; import x10.ast.X10ClassDecl; import x10.ast.X10ClassDecl_c; import x10.ast.X10ConstructorDecl; import x10.ast.X10FieldDecl; import x10.ast.X10Field_c; import x10.ast.X10Formal_c; import x10.ast.X10LocalAssign_c; import x10.ast.X10LocalDecl_c; import x10.ast.X10MethodDecl; import x10.ast.X10New_c; import x10.ast.X10NodeFactory_c; import x10.ast.X10SourceFile_c; import x10.ast.SettableAssign; import x10.constraint.XTerm; import x10.emitter.Emitter; import x10.extension.X10Ext; import x10.types.checker.Converter; import x10.types.constraints.CConstraint; import x10.types.ConstrainedType; import x10.types.ParameterType; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10ConstructorDef; import x10.types.X10ConstructorInstance; import x10.types.X10Def; import x10.types.X10MethodDef; import x10.types.MethodInstance; import x10.types.X10ProcedureDef; import x10.visit.Desugarer; import x10.visit.X10PrettyPrinterVisitor; import x10.visit.X10TypeChecker; import x10c.ast.X10CNodeFactory_c; import x10c.types.X10CTypeSystem_c; public class StaticInitializer extends ContextVisitor { // XTENLANG-3081(part2) private static final boolean checkExceptionInConstantExpression = true; // should be true private final X10CTypeSystem_c xts; private final X10CNodeFactory_c xnf; private final WeakHashMap<X10ProcedureDef,ProcedureDecl> procDeclCache; private final WeakHashMap<Block,Boolean> procBodyCache; public static final String initializerPrefix = "get$"; private static final String nestedShadowClass4Interface = "$Shadow"; // mapping static field and corresponding initializer method private Map<Pair<Type,Name>, StaticFieldInfo> staticFinalFields = CollectionFactory.newHashMap(); // for checking single vm mode private X10CompilerOptions opts = (X10CompilerOptions) job.extensionInfo().getOptions(); public StaticInitializer(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); xts = (X10CTypeSystem_c) ts; xnf = (X10CNodeFactory_c) nf; procBodyCache = new WeakHashMap<Block,Boolean>(); procDeclCache = new WeakHashMap<X10ProcedureDef,ProcedureDecl>(); } @Override protected Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { if (!(parent instanceof X10ClassDecl_c)) return n; X10ClassDecl_c ct = (X10ClassDecl_c)parent; if (old != ct.body()) return n; ClassBody classBody = (ClassBody) n; X10ClassDef classDef = ct.classDef(); assert(classDef != null); Context context = ct.enterChildScope(classBody, ((ContextVisitor) v).context()); // collect static fields to deal with staticFinalFields.clear(); // classBody.dump(System.err); // System.out.println("StaticInitilizer for "+classDef); classBody = checkStaticFields(classBody, context); if (staticFinalFields.isEmpty()) // nothing to do return classBody; List<ClassMember> currMembers = new ArrayList<ClassMember>(); currMembers.addAll(classBody.members()); if (!ct.flags().flags().isInterface()) { // create a new member list for initializer methods of each static field List<ClassMember> newMembers = createNewMembers(classDef); currMembers.addAll(newMembers); } else { // create a nested shadow class X10ClassDecl shadowDecl = createNestedShadowClass(ct); // create a new member list for the shadow class just created List<ClassMember> newMembers = createNewMembers(shadowDecl.classDef()); // add members into the body of the shadow class ClassBody shadowBody = shadowDecl.body(); shadowBody = shadowBody.members(newMembers); shadowDecl = shadowDecl.body(shadowBody); // add the shadow class in the original interface body currMembers.add(shadowDecl); } classBody = classBody.members(currMembers); // classBody.dump(System.err); return classBody; } private List<ClassMember> createNewMembers(X10ClassDef classDef) { Position CG = Position.compilerGenerated(null); List<ClassMember> members = new ArrayList<ClassMember>(); for (Map.Entry<Pair<Type,Name>, StaticFieldInfo> entry : staticFinalFields.entrySet()) { Name fName = entry.getKey().snd(); StaticFieldInfo fieldInfo = entry.getValue(); if (fieldInfo.right == null && fieldInfo.fieldDef == null) continue; MethodDecl md = null; if (fieldInfo.right != null) { // gen new field var FieldDecl fdExcept = makeFieldVar4Except(CG, fName, classDef); classDef.addField(fdExcept.fieldDef()); // add in the top members.add(0, fdExcept); FieldDecl fdCond = makeFieldVar4Guard(CG, fName, classDef); classDef.addField(fdCond.fieldDef()); // add in the top members.add(0, fdCond); FieldDecl fdId = makeFieldVar4Id(CG, fName, classDef); classDef.addField(fdId.fieldDef()); // add in the top members.add(0, fdId); if (fieldInfo.left != null) { // interface case: add field declaration to the shadow class FieldDef fd = fieldInfo.left.fieldDef(); Flags newFlags = fd.container().get().toClass().flags().clearInterface(); FieldDef newFd = xts.fieldDef(CG, Types.ref(classDef.asType()), newFlags, fd.type(), fd.name()); members.add(0, fieldInfo.left.fieldDef(newFd)); } // gen new initialize method md = makeInitMethod(CG, fName, fieldInfo, fdExcept.fieldDef(), fdCond.fieldDef(), fdId.fieldDef(), classDef); } else { md = makeFakeInitMethod(CG, fName, fieldInfo, classDef); } classDef.addMethod(md.methodDef()); // add in the bottom members.add(md); } return members; } private X10ClassDecl createNestedShadowClass(X10ClassDecl_c interfaceClass) { // create ClassDef first X10ClassDef cDef = createShadowClassDef(interfaceClass.classDef()); // create ClassDecl Position CG = Position.compilerGenerated(null); FlagsNode fNode = xnf.FlagsNode(CG, cDef.flags()); Id id = xnf.Id(CG, cDef.name()); TypeNode superTN = cDef.superType() != null ? xnf.CanonicalTypeNode(CG, cDef.superType()) : null; List<ClassMember> cmembers = new ArrayList<ClassMember>(); ClassBody body = xnf.ClassBody(CG, cmembers); List<TypeNode> interfaceTN = Collections.<TypeNode>emptyList(); X10ClassDecl cDecl = (X10ClassDecl) xnf.ClassDecl(CG, fNode, id, superTN, interfaceTN, body).classDef(cDef); return cDecl; } private X10ClassDef createShadowClassDef(X10ClassDef interfaceClassDef) { X10ClassDef cDef = (X10ClassDef) xts.createClassDef(interfaceClassDef.sourceFile()); List<Ref<? extends Type>> interfacesRef = new ArrayList<Ref<? extends Type>>(); interfacesRef.add(Types.ref(xts.Any())); cDef.setInterfaces(interfacesRef); cDef.name(Name.make(nestedShadowClass4Interface)); cDef.setFlags(Flags.PUBLIC.Abstract()); cDef.kind(ClassDef.MEMBER); cDef.outer(Types.ref(interfaceClassDef)); return cDef; } private ClassBody checkStaticFields(ClassBody body, Context context) { final X10ClassDef cd = context.currentClassDef(); // one pass scan of class body and collect vars for static initialization ClassBody c = (ClassBody)body.visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (n instanceof X10ClassDecl_c) { // should not visit subtree of inner class (already done) return n; } return null; } @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof X10FieldDecl) { X10FieldDecl fd = (X10FieldDecl)n; Flags flags = fd.fieldDef().flags(); if (isPerProcess(fd.fieldDef())) return n; if (flags.isFinal() && flags.isStatic()) { // static final field StaticFieldInfo fieldInfo = checkFieldDeclRHS((Expr)fd.init(), fd, cd); if (fieldInfo.right != null) { // drop final and set private (XTENLANG-3076) // System.out.println("RHS of FieldDecl replaced: "+ct.classDef()+"."+fd.fieldDef().name()); FlagsNode fn = xnf.FlagsNode(fd.position(), flags.clearFinal().clearPublic().clearProtected().Private()); // remove rhs: suppress java-level static initialization Expr init = getDefaultValue(fd.position(), fd.init().type()); FieldDecl newDecl = xnf.FieldDecl(fd.position(), fn, fd.type(), fd.name(), init).fieldDef(fd.fieldDef()); if (cd.flags().isInterface()) { // move the field declaration to a shadow class fieldInfo.left = newDecl; return null; } return newDecl; } } } if (n instanceof X10Field_c) { X10Field_c f = (X10Field_c)n; if (isPerProcess(f.fieldInstance().x10Def())) return n; if (f.flags().isFinal() && f.flags().isStatic()) { // found reference to static field if (checkFieldRefReplacementRequired(f)) { // replace with a static method call Type targetType = f.target().type(); if (targetType instanceof ParsedClassType) { X10ClassDef targetClassDef = ((ParsedClassType)targetType).def(); if (targetClassDef.flags().isInterface()) // target nested shadow class within interface targetType = createShadowClassDef(targetClassDef).asType(); } else if (targetType instanceof ConstrainedType) targetType = ((ConstrainedType)targetType).baseType().get(); X10ClassType receiver = (X10ClassType)targetType; return makeStaticCall(n.position(), receiver, f.name(), f.type()); } } } return n; }; }); return c; } private StaticFieldInfo checkFieldDeclRHS(Expr rhs, X10FieldDecl fd, X10ClassDef cd) { // traverse nodes in RHS Id leftName = fd.name(); // true means "found something not suitable for per-place initialization" final AtomicBoolean found = new AtomicBoolean(false); final boolean deep_analysis = opts.x10_config.STATICS_PER_PLACE_ANALYSIS; Expr newRhs = (Expr)rhs.visit(new NodeVisitor() { @Override public Node override(Node parent, Node n) { if (found.get()) // already found return n; if (n instanceof Expr) { if (isGlobalInit((Expr)n) || isConstraintToLiteral(((Expr)n).type())) { // initialization can be done in all places -- do not visit subtree further // System.out.println("isGlobalInit true in checkFieldDeclRHS: "+(Expr)n); return n; } if (n instanceof X10Call_c) { X10Call call = (X10Call)n; MethodInstance mi = call.methodInstance(); // if (!mi.container().isSubtype(xts.Object(), context)) { // // allow method calls on non-objects (including numerics, char and boolean) if (call.target().type().isNumeric() || call.target().type().isChar() || call.target().type().isBoolean()) { // allow method calls on numerics, char or boolean // XTENLANG-3081(part2) // exclude "1.operator/(0)" if (checkExceptionInConstantExpression) { found.set(true); return n; } } else if (deep_analysis && mi.flags().isStatic()) { // found reference to static method X10MethodDecl mdecl = getMethodDeclaration(mi); if (mdecl == null || checkProcedureBody(mdecl.body(), 0)) { // unsafe method call found.set(true); return n; } } else { // non-static method call or no deep analysis found.set(true); return n; } } else if (n instanceof X10Field_c) { X10Field_c f = (X10Field_c)n; if (f.flags().isFinal() && f.flags().isStatic()) { // found reference to static field if (checkFieldRefReplacementRequired(f)) { found.set(true); return n; } } } else if (n instanceof X10New_c) { if (deep_analysis) { X10New_c neu = (X10New_c)n; X10ConstructorInstance ci = neu.constructorInstance(); // get declaration of constructor X10ConstructorDecl cdecl = getConstructorDeclaration(ci); if (cdecl == null || checkProcedureBody(cdecl.body(), 0)) { // unsafe constructor found.set(true); return n; } } else { // deep analysis disabled found.set(true); return n; } } // XTENLANG-3081(part2) else { // exclude "1 as Any as Object" if (checkExceptionInConstantExpression) { found.set(true); return n; } } } // continue traversal return null; } }); // register original rhs X10ClassType receiver = cd.asType(); StaticFieldInfo fieldInfo = getFieldEntry(receiver, leftName.id()); fieldInfo.right = (fieldInfo.methodDef != null || found.get()) ? newRhs : null; fieldInfo.fieldDef = fd.fieldDef(); return fieldInfo; } private X10ConstructorDecl getConstructorDeclaration(X10ConstructorInstance ci) { X10ConstructorDef cd = ci.x10Def(); X10ClassType containerBase = (X10ClassType) Types.get(cd.container()); X10ClassDef container = containerBase.x10Def(); if (container == null) return null; return (X10ConstructorDecl)getProcedureDeclaration(cd, container); } private X10MethodDecl getMethodDeclaration(MethodInstance mi) { X10MethodDef md = mi.x10Def(); // get container and declaration for method X10ClassType containerBase = (X10ClassType) Types.get(md.container()); X10ClassDef container = containerBase.x10Def(); if (container == null) return null; return (X10MethodDecl)getProcedureDeclaration(md, container); } private ProcedureDecl getProcedureDeclaration(final X10ProcedureDef candidate, X10ClassDef container) { ProcedureDecl r = procDeclCache.get(candidate); if (r != null) return r; // obtain X10SourceFile ast of the target class that already runs preliminary compilation phases final Node ast = getAST(container); if (ast == null) return null; // find the target declaration of constructor or method final ProcedureDecl[] decl = new ProcedureDecl[1]; ast.visit(new NodeVisitor() { public Node override(Node n) { if (decl[0] != null) // already found the decl, short-circuit search return n; if (n instanceof X10FieldDecl) // not contain ctor decls, short-circuit search return n; if (n instanceof X10MethodDecl) { if (candidate == ((X10MethodDecl) n).methodDef()) { // found it!! decl[0] = (X10MethodDecl) n; } return n; } if (n instanceof X10ConstructorDecl) { if (candidate == ((X10ConstructorDecl) n).constructorDef()) { // found it!! decl[0] = (X10ConstructorDecl) n; } return n; } // continue traversal return null; } }); if (decl[0] == null || decl[0].body() == null) { return null; } procDeclCache.put(candidate, decl[0]); return decl[0]; } private Node getAST(X10ClassDef container) { // obtain the job for containing the constructor declaration Job job = container.job(); if (job == null || job.ast() == null) return null; if (job == this.job()) // current class return job.ast(); // run the preliminary compilation phases on the job's AST Node ast = job.ast(); assert (ast instanceof X10SourceFile_c); if (!((X10SourceFile_c) ast).hasBeenTypeChecked()) ast = ast.visit(new X10TypeChecker(job, ts, nf, job.nodeMemo()).begin()); if (ast == null) return null; if (!((X10Ext)ast.ext()).subtreeValid()) return null; ast = ast.visit(new Desugarer(job, ts, nf).begin()); return ast; } private boolean checkProcedureBody(final Block body, final int count) { Boolean r = procBodyCache.get(body); if (r != null) return (r == Boolean.TRUE); // Cut the search tree to avoid overly long compilation time. // True means centralized place-0 initialization is necessary, // which is a safe conservative assumption. if (count > 7) return true; // check static field references in the body of constructor or method final AtomicBoolean found = new AtomicBoolean(false); body.visit(new NodeVisitor() { public Node override(Node n) { if (found.get()) // already found return n; if (n instanceof Expr) { if (n instanceof X10Call) { X10Call call = (X10Call)n; MethodInstance mi = call.methodInstance(); // if (!mi.container().isSubtype(xts.Object(), context)) { // // allow method calls on non-objects (including numerics, char and boolean) if (call.target().type().isNumeric() || call.target().type().isChar() || call.target().type().isBoolean()) { // allow method calls on numerics, char or boolean // XTENLANG-3081(part2) // exclude "1.operator/(0)" if (checkExceptionInConstantExpression) { found.set(true); return n; } } else if (mi.flags().isStatic()) { // found reference to special initializer method X10MethodDecl mdecl = getMethodDeclaration(mi); if (mdecl == null || checkProcedureBody(mdecl.body(), count+1)) { // target method is unsafe include static field references found.set(true); return n; } } else { // we consider non-static method call as unsafe found.set(true); return n; } } else if (n instanceof X10Field_c) { X10Field_c f = (X10Field_c)n; if (f.flags().isFinal() && f.flags().isStatic()) { if (checkFieldRefReplacementRequired(f)) { // found reference to static field to be replaced found.set(true); return n; } } } else if (n instanceof X10New_c) { X10New_c neu = (X10New_c)n; X10ConstructorInstance ci = neu.constructorInstance(); // get declaration of constructor X10ConstructorDecl cdecl = getConstructorDeclaration(ci); if (cdecl != null && !cdecl.body().equals(body) && checkProcedureBody(cdecl.body(), count+1)) { // constructor include static field references to be replaced found.set(true); return n; } } // XTENLANG-3081(part2) else { // exclude "1 as Any as Object" if (checkExceptionInConstantExpression) { found.set(true); return n; } } } // continue traversal return null; } }); procBodyCache.put(body, found.get() ? Boolean.TRUE : Boolean.FALSE); return found.get(); } private Call makeStaticCall(Position pos, X10ClassType receiver, Id id, Type returnType) { // create MethodDef Name name = Name.make(initializerPrefix+id); StaticFieldInfo fieldInfo = getFieldEntry(receiver, id.id()); MethodDef md = fieldInfo.methodDef; if (md == null) { md = makeMethodDef(pos, receiver, name, returnType); fieldInfo.methodDef = md; } // create static call for initialization List<TypeNode> typeArgsN = Collections.<TypeNode>emptyList(); List<Expr> args = Collections.<Expr>emptyList(); MethodInstance mi = xts.createMethodInstance(pos, pos, Types.ref(md)); Call result = (Call) xnf.X10Call(pos, xnf.CanonicalTypeNode(pos, receiver), xnf.Id(pos, name), typeArgsN, args) .methodInstance(mi).type(returnType); return result; } private MethodDef makeMethodDef(Position pos, X10ClassType receiver, Name name, Type returnType) { Position CG = Position.compilerGenerated(null); List<Ref<? extends Type>> argTypes = Collections.<Ref<? extends Type>>emptyList(); MethodDef md = xts.methodDef(CG, CG, Types.ref(receiver), Flags.STATIC, Types.ref(returnType), name, argTypes, Collections.<Ref<? extends Type>>emptyList()); return md; } private FieldDecl makeFieldVar4Guard(Position pos, Name fName, X10ClassDef classDef) { // make FieldDef of AtomicInteger ClassType type = (ClassType)xts.AtomicInteger(); Flags flags = Flags.PRIVATE.Static().Final(); Name name = Name.make("initStatus$"+fName); FieldDef fd = xts.fieldDef(pos, Types.ref(classDef.asType()), flags, Types.ref(type), name); FieldInstance fi = xts.createFieldInstance(pos, Types.ref(fd)); // create right hand side: new AtomicInteger(UNINITIALIZED) TypeNode tn = xnf.X10CanonicalTypeNode(pos, type); List<Expr> args = new ArrayList<Expr>(); args.add(getInitDispatcherConstant(pos, "UNINITIALIZED").type(xts.Int())); ConstructorDef cd = xts.defaultConstructor(pos, pos, Types.ref(type)); ConstructorInstance ci = xts.createConstructorInstance(pos, pos, Types.ref(cd)); Expr init = xnf.New(pos, tn, args).constructorInstance(ci).type(type); // fieldDecl and its association with fieldDef FieldDecl result = xnf.FieldDecl(pos, xnf.FlagsNode(pos, flags), tn, xnf.Id(pos, name), init); result = result.fieldDef(fd); return result; } private FieldDecl makeFieldVar4Except(Position pos, Name fName, X10ClassDef classDef) { // make FieldDef of x10.lang.ExceptionInInitializer ClassType type = ExceptionInInitializer(); Flags flags = Flags.PRIVATE.Static(); Name name = Name.make("exception$"+fName); FieldDef fd = xts.fieldDef(pos, Types.ref(classDef.asType()), flags, Types.ref(type), name); FieldInstance fi = xts.createFieldInstance(pos, Types.ref(fd)); // create field declaration node TypeNode tn = xnf.X10CanonicalTypeNode(pos, type); FieldDecl result = xnf.FieldDecl(pos, xnf.FlagsNode(pos, flags), tn, xnf.Id(pos, name)); result = result.fieldDef(fd); return result; } private FieldDecl makeFieldVar4Id(Position pos, Name fName, X10ClassDef classDef) { // make FieldDef Type type = xts.Short(); Name name = Name.make("fieldId$"+fName); Flags flags = Flags.PRIVATE.Static(); FieldDef fd = xts.fieldDef(pos, Types.ref(classDef.asType()), flags, Types.ref(type), name); FieldInstance fi = xts.createFieldInstance(pos, Types.ref(fd)); // create the field declaration node TypeNode tn = xnf.X10CanonicalTypeNode(pos, type); FieldDecl result = xnf.FieldDecl(pos, xnf.FlagsNode(pos, flags), tn, xnf.Id(pos, name)); // associate fieldDef with fieldDecl result = result.fieldDef(fd); return result; } private Expr getDefaultValue(Position pos, Type type) { if (type.isBoolean()) return xnf.BooleanLit(pos, false).type(type); else if (type.isChar()) return xnf.CharLit(pos, '\0').type(type); else if (type.isByte() || type.isShort() || type.isInt()) return xnf.IntLit(pos, IntLit.INT, 0).type(type); else if (type.isLong()) return xnf.IntLit(pos, IntLit.LONG, 0).type(type); else if (type.isUByte() || type.isUShort() || type.isUInt()) return xnf.IntLit(pos, IntLit.UINT, 0).type(type); else if (type.isULong()) return xnf.IntLit(pos, IntLit.ULONG, 0).type(type); else if (type.isFloat()) return xnf.FloatLit(pos, FloatLit.FLOAT, 0.0).type(type); else if (type.isDouble()) return xnf.FloatLit(pos, FloatLit.DOUBLE, 0.0).type(type); else if (type.isString()) return xnf.NullLit(pos).type(type); else return null; } private MethodDecl makeInitMethod(Position pos, Name fName, StaticFieldInfo fieldInfo, FieldDef fdExcept, FieldDef fdCond, FieldDef fdId, X10ClassDef classDef) { // get MethodDef Name name = Name.make(initializerPrefix+fName); Type type = fieldInfo.fieldDef.type().get(); MethodDef md = fieldInfo.methodDef; if (md == null) { md = makeMethodDef(pos, classDef.asType(), name, type); } // create a method declaration node List<TypeParamNode> typeParamNodes = Collections.<TypeParamNode>emptyList(); List<Formal> formals = Collections.<Formal>emptyList(); TypeNode returnType = xnf.X10CanonicalTypeNode(pos, type); Block body = makeInitMethodBody(pos, fieldInfo, fdExcept, fdCond, fdId, classDef); MethodDecl result = xnf.X10MethodDecl(pos, xnf.FlagsNode(pos, Flags.STATIC), returnType, xnf.Id(pos, name), typeParamNodes, formals, null, null, Collections.<TypeNode>emptyList(), body); // associate methodDef with methodDecl result = result.methodDef(md); return result; } private Catch genCatch(Position pos, FieldDef fdExcept, FieldDef fdCond, Name excName, X10ClassType excType, TypeNode receiver, Stmt throwExceptStmt) { LocalDef excDef = xts.localDef(pos, Flags.NONE, Types.ref(excType), excName); Formal excFormal = xnf.Formal(pos, xnf.FlagsNode(pos, excDef.flags()), xnf.CanonicalTypeNode(pos, excDef.type()), xnf.Id(pos, excDef.name())).localDef(excDef); List<Ref<? extends Type>> newExceptArgTypes = new ArrayList<Ref<? extends Type>>(); newExceptArgTypes.add(Types.ref(xts.Exception())); ConstructorDef cd = xts.constructorDef(pos, pos, Types.ref(fdExcept.asInstance().type().toClass()), Flags.NONE, newExceptArgTypes, Collections.<Ref<? extends Type>>emptyList()); ConstructorInstance ci = xts.createConstructorInstance(pos, pos, Types.ref(cd)); List<Expr> newExceptArgs = new ArrayList<Expr>(); Expr excExpr = xnf.Local(pos, xnf.Id(pos, excDef.name())).localInstance(excDef.asInstance()).type(excDef.asInstance().type()); newExceptArgs.add(excExpr); Expr newExceptExpr = xnf.New(pos, xnf.CanonicalTypeNode(pos, fdExcept.asInstance().type()), newExceptArgs).constructorInstance(ci).type(fdExcept.asInstance().type()); Stmt storeExceptStmt = xnf.Eval(pos, xnf.FieldAssign(pos, receiver, xnf.Id(pos, fdExcept.name()), Assign.ASSIGN, newExceptExpr).fieldInstance(fdExcept.asInstance()).type(fdExcept.asInstance().type())); List<Stmt> catchStmts = new ArrayList<Stmt>(); // gen exception = new x10.lang.ExceptionInInitializer(e); catchStmts.add(storeExceptStmt); // gen AtomicInteger.set(EXCEPTION_RAISED) catchStmts.add(xnf.Eval(pos, genStatusSetExcept(pos, receiver, fdCond))); // gen lockInitialized() catchStmts.add(xnf.Eval(pos, genLock(pos))); // gen notifyInitialized() catchStmts.add(xnf.Eval(pos, genNotify(pos))); // gen throw exception; catchStmts.add(throwExceptStmt); return xnf.Catch(pos, excFormal, xnf.Block(pos, catchStmts)); } private Catch genCatchWithMessage(Position pos, FieldDef fdExcept, FieldDef fdCond, Name excName, X10ClassType excType, TypeNode receiver, Stmt throwExceptStmt) { LocalDef excDef = xts.localDef(pos, Flags.NONE, Types.ref(excType), excName); Formal excFormal = xnf.Formal(pos, xnf.FlagsNode(pos, excDef.flags()), xnf.CanonicalTypeNode(pos, excDef.type()), xnf.Id(pos, excDef.name())).localDef(excDef); List<Ref<? extends Type>> newExceptArgTypes = new ArrayList<Ref<? extends Type>>(); newExceptArgTypes.add(Types.ref(xts.String())); ConstructorDef cd = xts.constructorDef(pos, pos, Types.ref(fdExcept.asInstance().type().toClass()), Flags.NONE, newExceptArgTypes, Collections.<Ref<? extends Type>>emptyList()); ConstructorInstance ci = xts.createConstructorInstance(pos, pos, Types.ref(cd)); List<Expr> newExceptArgs = new ArrayList<Expr>(); MethodDef md = xts.methodDef(pos, pos, (Ref<? extends ContainerType>) excDef.type(), Flags.NONE, Types.ref(xts.String()), Name.make("getMessage"), Collections.<Ref<? extends Type>>emptyList(), Collections.<Ref<? extends Type>>emptyList()); MethodInstance mi = xts.createMethodInstance(pos, pos, Types.ref(md)); Expr excExpr = xnf.Local(pos, xnf.Id(pos, excDef.name())).localInstance(excDef.asInstance()).type(excDef.asInstance().type()); Expr call = xnf.X10Call(pos, excExpr, xnf.Id(pos, mi.name()), Collections.<TypeNode>emptyList(), Collections.<Expr>emptyList()).methodInstance(mi).type(mi.returnType()); newExceptArgs.add(call); Expr newExceptExpr = xnf.New(pos, xnf.CanonicalTypeNode(pos, fdExcept.asInstance().type()), newExceptArgs).constructorInstance(ci).type(fdExcept.asInstance().type()); Stmt storeExceptStmt = xnf.Eval(pos, xnf.FieldAssign(pos, receiver, xnf.Id(pos, fdExcept.name()), Assign.ASSIGN, newExceptExpr).fieldInstance(fdExcept.asInstance()).type(fdExcept.asInstance().type())); List<Stmt> catchStmts = new ArrayList<Stmt>(); // gen exception = new x10.lang.ExceptionInInitializer(e.getMessage()); catchStmts.add(storeExceptStmt); // gen AtomicInteger.set(EXCEPTION_RAISED) catchStmts.add(xnf.Eval(pos, genStatusSetExcept(pos, receiver, fdCond))); // gen lockInitialized() catchStmts.add(xnf.Eval(pos, genLock(pos))); // gen notifyInitialized() catchStmts.add(xnf.Eval(pos, genNotify(pos))); // gen throw exception; catchStmts.add(throwExceptStmt); return xnf.Catch(pos, excFormal, xnf.Block(pos, catchStmts)); } private Block makeInitMethodBody(Position pos, StaticFieldInfo initInfo, FieldDef fdExcept, FieldDef fdCond, FieldDef fdId, X10ClassDef classDef) { List<Stmt> stmts; TypeNode receiver = xnf.X10CanonicalTypeNode(pos, classDef.asType()); FieldInstance fi = initInfo.fieldDef.asInstance(); Expr right = initInfo.right; Name name = initInfo.fieldDef.name(); Expr left = xnf.Field(pos, receiver, xnf.Id(pos, name)).fieldInstance(fi).type(right.type()); // gen if (AtomicInteger.get() == INITIALIZED) { return field; } stmts = new ArrayList<Stmt>(); stmts.add(xnf.X10Return(pos, left, false)); Stmt shortCutBlock = xnf.If(pos, genCheckInitialized(pos, receiver, fdCond, true), xnf.Block(pos, stmts)); Stmt shortCutBlockExcept = null; Stmt throwExceptStmt = null; // gen if (AtomicInteger.get() == EXCEPTION_RAISED) { throw exception; } stmts = new ArrayList<Stmt>(); stmts.add(xnf.If(pos, genPrintStmtCheckGuard(pos), makePrintStmtExcept(pos, name, classDef))); throwExceptStmt = xnf.Throw(pos, xnf.Field(pos, receiver, xnf.Id(pos, fdExcept.name())).fieldInstance(fdExcept.asInstance()).type(fdExcept.asInstance().type())); stmts.add(throwExceptStmt); shortCutBlockExcept = xnf.If(pos, genCheckExceptionRaised(pos, receiver, fdCond, true), xnf.Block(pos, stmts)); // gen AtomicInteger.compareAndSet(UNINITIALIZED, INITIALIZING) Expr ifCond = genAtomicGuard(pos, receiver, fdCond); FieldInstance fdidi = fdId.asInstance(); Expr fieldId = xnf.Field(pos, receiver, xnf.Id(pos, fdId.name())).fieldInstance(fdidi).type(fdidi.type()); // make statement block of initialization stmts = new ArrayList<Stmt>(); // if (stickyExceptionSemantics) surround with try Stmt fieldAssignStmt = xnf.Eval(pos, xnf.FieldAssign(pos, receiver, xnf.Id(pos, name), Assign.ASSIGN, right).fieldInstance(fi).type(right.type())); Name excName = Name.makeFresh("exc$"); List<Catch> catchBlocks = new ArrayList<Catch>(); // gen catch (java.lang.Throwable exc) { exception = new x10.lang.ExceptionInInitializer(exc); AtomicInteger.set(EXCEPTION_RAISED); lockInitialized(); notifyInitialized(); throw exception; } catchBlocks.add(genCatch(pos, fdExcept, fdCond, excName, xts.CheckedThrowable(), receiver, throwExceptStmt)); stmts.add(xnf.Try(pos, xnf.Block(pos, fieldAssignStmt), catchBlocks)); stmts.add(xnf.If(pos, genPrintStmtCheckGuard(pos), makePrintStmt(pos, name, classDef))); stmts.add(xnf.Eval(pos, genStatusSet(pos, receiver, fdCond))); stmts.add(xnf.Eval(pos, genLock(pos))); stmts.add(xnf.Eval(pos, genNotify(pos))); Block initBody = xnf.Block(pos, stmts); // gen while(AtomicInteger.get() != INITIALIZED) { await(); } Expr initCheckCond = genCheckInitialized(pos, receiver, fdCond, Binary.LT); Block whileBody = xnf.Block(pos, xnf.Eval(pos, genAwait(pos))); // make statement block for waiting stmts = new ArrayList<Stmt>(); stmts.add(xnf.Eval(pos, genLock(pos))); stmts.add(xnf.While(pos, initCheckCond, whileBody)); stmts.add(xnf.Eval(pos, genUnlock(pos))); stmts.add(shortCutBlockExcept); Block waitBody = xnf.Block(pos, stmts); // make statement block of the entire method body stmts = new ArrayList<Stmt>(); stmts.add(shortCutBlock); stmts.add(shortCutBlockExcept); // original // stmts.add(xnf.If(pos, initCheckCond, waitBody)); // optimized stmts.add(xnf.If(pos, ifCond, initBody, xnf.If(pos, initCheckCond, waitBody))); stmts.add(xnf.X10Return(pos, left, false)); Block body = xnf.Block(pos, stmts); return body; } private Expr genAtomicGuard(Position pos, TypeNode receiver, FieldDef fdCond) { FieldInstance fi = fdCond.asInstance(); Expr ai = xnf.Field(pos, receiver, xnf.Id(pos, fdCond.name())).fieldInstance(fi).type(fi.type()); Id cs = xnf.Id(pos, Name.make("compareAndSet")); List<Ref<? extends Type>> argTypes = new ArrayList<Ref<? extends Type>>(); argTypes.add(Types.ref(xts.Int())); argTypes.add(Types.ref(xts.Int())); MethodDef md = xts.methodDef(pos, pos, Types.ref((ClassType) xts.AtomicInteger()), Flags.NONE, Types.ref(xts.Boolean()), cs.id(), argTypes, Collections.<Ref<? extends Type>>emptyList()); MethodInstance mi = xts.createMethodInstance(pos, pos, Types.ref(md)); List<Expr> args = new ArrayList<Expr>(); args.add(getInitDispatcherConstant(pos, "UNINITIALIZED").type(xts.Int())); args.add(getInitDispatcherConstant(pos, "INITIALIZING").type(xts.Int())); List<TypeNode> typeParamNodes = new ArrayList<TypeNode>(); typeParamNodes.add(xnf.CanonicalTypeNode(pos, xts.Int())); typeParamNodes.add(xnf.CanonicalTypeNode(pos, xts.Int())); Expr call = xnf.X10Call(pos, ai, cs, typeParamNodes, args).methodInstance(mi).type(xts.Boolean()); return call; } private Expr genStatusSet(Position pos, TypeNode receiver, FieldDef fdCond) { return genStatusSet(pos, "INITIALIZED", receiver, fdCond); } private Expr genStatusSetExcept(Position pos, TypeNode receiver, FieldDef fdCond) { return genStatusSet(pos, "EXCEPTION_RAISED", receiver, fdCond); } private Expr genStatusSet(Position pos, String status, TypeNode receiver, FieldDef fdCond) { FieldInstance fi = fdCond.asInstance(); Expr ai = xnf.Field(pos, receiver, xnf.Id(pos, fdCond.name())).fieldInstance(fi).type(fi.type()); Id name = xnf.Id(pos, Name.make("set")); // Intentionally not SettableAssign.SET because AtomicInteger is a NativeRep class List<Ref<? extends Type>> argTypes = new ArrayList<Ref<? extends Type>>(); argTypes.add(Types.ref(xts.Int())); MethodDef md = xts.methodDef(pos, pos, Types.ref((ClassType)xts.AtomicInteger()), Flags.NONE, Types.ref(xts.Void()), name.id(), argTypes, Collections.<Ref<? extends Type>>emptyList()); MethodInstance mi = xts.createMethodInstance(pos, pos, Types.ref(md)); List<Expr> args = new ArrayList<Expr>(); args.add(getInitDispatcherConstant(pos, status).type(xts.Int())); List<TypeNode> typeParamNodes = new ArrayList<TypeNode>(); typeParamNodes.add(xnf.CanonicalTypeNode(pos, xts.Int())); Expr call = xnf.X10Call(pos, ai, name, typeParamNodes, args).methodInstance(mi).type(xts.Void()); return call; } private Expr genCheckInitialized(Position pos, TypeNode receiver, FieldDef fdCond, boolean positive) { return genCheckInitialized(pos, receiver, fdCond, positive ? Binary.EQ : Binary.NE); } private Expr genCheckExceptionRaised(Position pos, TypeNode receiver, FieldDef fdCond, boolean positive) { return genCheckExceptionRaised(pos, receiver, fdCond, positive ? Binary.EQ : Binary.NE); } private Expr genCheckInitialized(Position pos, TypeNode receiver, FieldDef fdCond, Operator op) { return genCheck(pos, receiver, "INITIALIZED", fdCond, op); } private Expr genCheckExceptionRaised(Position pos, TypeNode receiver, FieldDef fdCond, Operator op) { return genCheck(pos, receiver, "EXCEPTION_RAISED", fdCond, op); } private Expr genCheck(Position pos, TypeNode receiver, String fieldName, FieldDef fdCond, Operator op) { FieldInstance fi = fdCond.asInstance(); Expr ai = xnf.Field(pos, receiver, xnf.Id(pos, fdCond.name())).fieldInstance(fi).type(fi.type()); Id name = xnf.Id(pos, Name.make("get")); List<Ref<? extends Type>> argTypes = Collections.<Ref<? extends Type>>emptyList(); MethodDef md = xts.methodDef(pos, pos, Types.ref((ClassType)xts.AtomicInteger()), Flags.NONE, Types.ref(xts.Int()), name.id(), argTypes, Collections.<Ref<? extends Type>>emptyList()); MethodInstance mi = xts.createMethodInstance(pos, pos, Types.ref(md)); List<Expr> args = Collections.<Expr>emptyList(); List<TypeNode> typeParamNodes = Collections.<TypeNode>emptyList(); Expr call = xnf.X10Call(pos, ai, name, typeParamNodes, args).methodInstance(mi).type(xts.Int()); return xnf.Binary(pos, call, op, getInitDispatcherConstant(pos, fieldName).type(xts.Int())).type(xts.Boolean()); } private Expr genLock(Position pos) { return callInitDispatcherMethodVoidNoarg(pos, Name.make("lockInitialized")); } private Expr genUnlock(Position pos) { return callInitDispatcherMethodVoidNoarg(pos, Name.make("unlockInitialized")); } private Expr genAwait(Position pos) { return callInitDispatcherMethodVoidNoarg(pos, Name.make("awaitInitialized")); } private Expr genNotify(Position pos) { return callInitDispatcherMethodVoidNoarg(pos, Name.make("notifyInitialized")); } private Expr callInitDispatcherMethodVoidNoarg(Position pos, Name methodName) { // create MethodDef Id id = xnf.Id(pos, methodName); List<Ref<? extends Type>> argTypes = Collections.<Ref<? extends Type>>emptyList(); MethodDef md = xts.methodDef(pos, pos, Types.ref(InitDispatcher()), Flags.NONE, Types.ref(xts.Void()), id.id(), argTypes, Collections.<Ref<? extends Type>>emptyList()); MethodInstance mi = xts.createMethodInstance(pos, pos, Types.ref(md)); // actual arguments List<Expr> args = Collections.<Expr>emptyList(); List<TypeNode> typeParamNodes = Collections.<TypeNode>emptyList(); Receiver receiver = xnf.CanonicalTypeNode(pos, InitDispatcher()); Expr call = xnf.X10Call(pos, receiver, id, typeParamNodes, args).methodInstance(mi).type(xts.Void()); return call; } private Expr getInitDispatcherConstant(Position pos, String name) { Id id = xnf.Id(pos, Name.make(name)); FieldDef fd = xts.fieldDef(pos, Types.ref(InitDispatcher()), Flags.STATIC, Types.ref(xts.Int()), id.id()); FieldInstance fi = xts.createFieldInstance(pos, Types.ref(fd)); Receiver receiver = xnf.CanonicalTypeNode(pos, InitDispatcher()); return xnf.Field(pos, receiver, id).fieldInstance(fi); } private MethodDecl makeFakeInitMethod(Position pos, Name fName, StaticFieldInfo fieldInfo, X10ClassDef classDef) { // get MethodDef Name name = Name.make(initializerPrefix+fName); FieldInstance fi = fieldInfo.fieldDef.asInstance(); MethodDef md = makeMethodDef(pos, classDef.asType(), name, fi.type()); // create a method declaration node List<TypeParamNode> typeParamNodes = Collections.<TypeParamNode>emptyList(); List<Formal> formals = Collections.<Formal>emptyList(); // get field reference if (classDef.isMember() && classDef.outer().get().flags().isInterface()) // should refer to fields in the outer interface classDef = (X10ClassDef)classDef.outer().get(); TypeNode receiver = xnf.X10CanonicalTypeNode(pos, classDef.asType()); Expr left = xnf.Field(pos, receiver, xnf.Id(pos, fieldInfo.fieldDef.name())).fieldInstance(fi).type(fi.type()); // make statement block List<Stmt> stmts = new ArrayList<Stmt>(); stmts.add(xnf.X10Return(pos, left, false)); Block body = xnf.Block(pos, stmts); // create method declaration TypeNode returnType = xnf.X10CanonicalTypeNode(pos, fi.type()); MethodDecl result = xnf.X10MethodDecl(pos, xnf.FlagsNode(pos, Flags.STATIC), returnType, xnf.Id(pos, name), typeParamNodes, formals, null, null, Collections.<TypeNode>emptyList(), body); // associate methodDef with methodDecl result = result.methodDef(md); return result; } private ClassType X10JavaSerializable_; private ClassType X10JavaSerializable() { if (X10JavaSerializable_ == null) X10JavaSerializable_ = xts.load("x10.compiler.X10JavaSerializable"); return X10JavaSerializable_; } private ClassType X10JavaDeserializer_; private ClassType X10JavaDeserializer() { if (X10JavaDeserializer_ == null) X10JavaDeserializer_ = xts.load("x10.compiler.X10JavaDeserializer"); return X10JavaDeserializer_; } private ClassType InitDispatcher_; private ClassType InitDispatcher() { if (InitDispatcher_ == null) InitDispatcher_ = xts.load("x10.compiler.InitDispatcher"); return InitDispatcher_; } private ClassType PlaceLocalHandle_; private ClassType PlaceLocalHandle() { if (PlaceLocalHandle_ == null) PlaceLocalHandle_ = xts.load("x10.compiler.PlaceLocalHandle"); return PlaceLocalHandle_; } private ClassType ExceptionInInitializer_; private ClassType ExceptionInInitializer() { if (ExceptionInInitializer_ == null) ExceptionInInitializer_ = xts.load("x10.lang.ExceptionInInitializer"); return ExceptionInInitializer_; } private Stmt makePrintStmt(Position pos, Name fieldName, X10ClassDef classDef) { // get fully qualified field name String fullName = getPackageName(classDef) + getClassName(classDef) + "." + Emitter.mangleToJava(fieldName); return makePrintStmt(pos, "Doing static initialization for field: " + fullName, classDef); } private Stmt makePrintStmtExcept(Position pos, Name fieldName, X10ClassDef classDef) { // get fully qualified field name String fullName = getPackageName(classDef) + getClassName(classDef) + "." + Emitter.mangleToJava(fieldName); return makePrintStmt(pos, "Rethrowing ExceptionInInitializer for field: " + fullName, classDef); } private Stmt makePrintStmt(Position pos, String message, X10ClassDef classDef) { Id id = xnf.Id(pos, Name.make("printStaticInitMessage")); // argument type List<Ref<? extends Type>> argTypes = new ArrayList<Ref<? extends Type>>(); argTypes.add(Types.ref(xts.String())); // create MethodDef MethodDef md = xts.methodDef(pos, pos, Types.ref(InitDispatcher()), Flags.NONE, Types.ref(xts.Void()), id.id(), argTypes, Collections.<Ref<? extends Type>>emptyList()); MethodInstance mi = xts.createMethodInstance(pos, pos,Types.ref(md)); // actual arguments List<Expr> args = new ArrayList<Expr>(); args.add(xnf.StringLit(pos, message).type(xts.String())); List<TypeNode> typeParamNodes = new ArrayList<TypeNode>(); typeParamNodes.add(xnf.CanonicalTypeNode(pos, xts.String())); TypeNode receiver = xnf.CanonicalTypeNode(pos, InitDispatcher()); return xnf.Eval(pos, xnf.X10Call(pos, receiver, id, typeParamNodes, args).methodInstance(mi).type(xts.Void())); } private Expr genPrintStmtCheckGuard(Position pos) { Id name = xnf.Id(pos, Name.make("TRACE_STATIC_INIT")); FieldDef fieldDef = xts.fieldDef(pos, Types.ref(InitDispatcher()), Flags.STATIC, Types.ref(xts.Boolean()), name.id()); X10FieldInstance fi = xts.createFieldInstance(pos, Types.ref(fieldDef)); Receiver receiver = xnf.CanonicalTypeNode(pos, InitDispatcher()); Expr left = xnf.Field(pos, receiver, name).fieldInstance(fi); return xnf.Binary(pos, left.type(xts.Boolean()), Binary.EQ, xnf.BooleanLit(pos, true).type(xts.Boolean())); } private String getClassName(ClassDef classDef) { String name = classDef.name().toString(); if (classDef.isNested()) { ClassDef outer = Types.get(classDef.outer()); if (outer != null) // get outer's name recursively name = getClassName(outer) +'$' + name; } return name; } private String getPackageName(ClassDef classDef) { if (classDef.isNested()) return getPackageName(Types.get(classDef.outer())); Package p = Types.get(classDef.package_()); return (p != null ? p.toString() + "." : ""); } private StaticFieldInfo getFieldEntry(Type target, Name name) { Pair<Type,Name> key = new Pair<Type,Name>(target, name); StaticFieldInfo fieldInfo = staticFinalFields.get(key); if (fieldInfo == null) { fieldInfo = new StaticFieldInfo(); staticFinalFields.put(key, fieldInfo); } return fieldInfo; } private boolean isGlobalInit(Expr e) { // N.B. Process safe cast as constant if (e instanceof Cast) return isConstantExpression(e); if (e.type().isNumeric() || e.type().isBoolean() || e.type().isChar() || e.type().isNull()) return isConstantExpression(e); if (e.type().isString()) return isStringConstant(e); return false; } private static boolean isSafeCast(Cast c, Context context) { return c.expr().type().isSubtype(c.castType().type(), context); } /** * from x10cpp.visit.ASTQuery */ private boolean isConstantExpression(Expr e) { // N.B. Need to check first because NullLit_c.isConstant() returns false to workaround constant propagator's bug! if (e instanceof NullLit) return true; // N.B. Process safe cast as constant if (e instanceof Cast) { Cast c = (Cast) e; return isConstantExpression(c.expr()) && isSafeCast(c, context); } if (!e.isConstant()) return false; if (e instanceof BooleanLit) return true; if (e instanceof IntLit) return true; if (e instanceof FloatLit) return true; if (e instanceof CharLit) return true; // N.B. Process safe cast as constant // if (e instanceof Cast) // return isConstantExpression(((Cast) e).expr()); if (e instanceof ParExpr) return isConstantExpression(((ParExpr) e).expr()); if (e instanceof Unary) return isConstantExpression(((Unary) e).expr()); if (e instanceof Binary) return isConstantExpression(((Binary) e).left()) && isConstantExpression(((Binary) e).right()); if (e instanceof Conditional) return isConstantExpression(((Conditional) e).cond()) && isConstantExpression(((Conditional) e).consequent()) && isConstantExpression(((Conditional) e).alternative()); if (e instanceof Closure) { Closure c = (Closure) e; List<Stmt> ss = c.body().statements(); if (ss.size() != 1) return false; if (!(ss.get(0) instanceof Return)) return false; return isConstantExpression(((Return) ss.get(0)).expr()); } if (e instanceof ClosureCall) { ClosureCall cc = (ClosureCall) e; List<Expr> as = ((ClosureCall) e).arguments(); for (Expr a : as) { if (!isConstantExpression(a)) return false; } return isConstantExpression(cc.target()); } if (e instanceof Call) { Call c = (Call) e; return c.isConstant(); } return false; } private boolean isStringConstant(Expr e) { if (!e.isConstant()) return false; if (e instanceof StringLit) return true; if (e instanceof X10Call) { // check if this is string manipulation (e.g. concatenation) X10Call call = (X10Call)e; List<Expr> args = call.arguments(); for (Expr arg : args) { if (!isStringConstant(arg)) return false; } Type targetType = call.target().type(); if (targetType instanceof ConstrainedType) targetType = ((ConstrainedType)targetType).baseType().get(); return targetType.isString(); } return false; } private boolean checkFieldRefReplacementRequired(X10Field_c f) { if (f.target().type().toClass().isJavaType()) return false; if (f.target().type().isNumeric()) // @NativeRep class should be excluded return false; if (f.isConstant()) return false; if (isConstraintToLiteral(f.type())) return false; Pair<Type,Name> key = new Pair<Type,Name>(f.target().type(), f.name().id()); StaticFieldInfo fieldInfo = staticFinalFields.get(key); // not yet registered, or registered as replacement required return fieldInfo == null || fieldInfo.right != null || fieldInfo.methodDef != null; } private boolean isConstraintToLiteral(Type type) { if (type instanceof ConstrainedType) { // check if self is bound to a constant ConstrainedType ct = (ConstrainedType)(type); if (ct.constraint().known()) { CConstraint cc = ct.constraint().get(); XTerm selfVar = cc.selfVarBinding(); if (selfVar != null && selfVar.isLit()) return true; } } return false; } static class StaticFieldInfo { Expr right; // RHS expression, if replaced with initialization method MethodDef methodDef; // getInitialized methodDef to be replaced FieldDef fieldDef; FieldDecl left; // field declaration to be moved from interface to a shadow class } protected boolean isPerProcess(X10Def def) { try { Type t = xts.systemResolver().findOne(QName.make("x10.compiler.PerProcess")); return !def.annotationsMatching(t).isEmpty(); } catch (SemanticException e) { return false; } } }