/* * 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 2010. */ package x10.optimizations.inlining; import java.util.Map; import polyglot.ast.Call; import polyglot.ast.ConstructorCall; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.ProcedureDecl; import polyglot.ast.Receiver; import polyglot.ast.Special; import polyglot.frontend.CyclicDependencyException; import polyglot.frontend.Goal; import polyglot.frontend.Job; import polyglot.frontend.Scheduler; import polyglot.types.ClassType; import polyglot.types.MemberDef; import polyglot.types.ProcedureDef; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import x10.Configuration; import x10.X10CompilerOptions; import x10.ast.ClosureCall; import x10.ast.InlinableCall; import x10.optimizations.Optimizer; import x10.types.X10ProcedureDef; import x10.util.CollectionFactory; /** * @author Bowen Alpern */ public class DeclStore { private static final boolean DEBUG = false; private final TypeSystem ts; private final NodeFactory nf; private final Map<String, DeclPackage> declPackages; private Job job; private InlineUtils utils; private int implicitMax; private boolean initialized; private DeclPackage ambiguousDef; public DeclStore(TypeSystem ts, NodeFactory nf) { this.ts = ts; this.nf = nf; declPackages = CollectionFactory.newHashMap(); initialized = false; ambiguousDef = new DeclPackage("ProcecureDef does not contain necessary position information to disambiguate ProcedureDecl"); } public void startJob (Job j) { job = j; if (!initialized) { // this stuff needs a Job (any Job) to initialize but is otherwise final initialized = true; utils = new InlineUtils(job); Configuration c = ((X10CompilerOptions) job.extensionInfo().getOptions()).x10_config; int impCalls = c.INLINE_SIZE + (c.EXPERIMENTAL ? 1 : 0); implicitMax = (impCalls+1)*CostDelegate.CALL_COST - 1; assert c.OPTIMIZE && (c.INLINE || 0 < c.INLINE_SIZE); } } /** * @param call * @return */ ProcedureDecl retrieveDecl(InlinableCall call) { X10ProcedureDef def = getDef(call); DeclPackage pkg = getDeclPackage(def); if (null == pkg) { try { Job job = ((ClassType) Types.baseType(((MemberDef) def).container().get())).def().job(); if (null == job || null == job.extensionInfo() || null == job.extensionInfo().scheduler()) return null; Scheduler scheduler = job.extensionInfo().scheduler(); Goal goal = new Optimizer(scheduler, job).Packager(); if (!scheduler.attempt(goal)) { // throw ICE ?? putDeclPackage(def, new DeclPackage("job for candidate does not compile: " +def)); return null; } } catch (CyclicDependencyException e) { // this should never happen putDeclPackage(def, new DeclPackage("job for candidate does not compile: " +def+ " (" +e+ ")")); throw new InternalCompilerError("If A ->* B, A is at Harvester & ? -> A would break any cycle", call.position(), e); } pkg = getDeclPackage(def); assert null != pkg : "def="+def+" call="+call+" pos1="+def.position()+" pos2="+call.position(); // FIXME this assertion may fail if a class overrides a final method of its super class. } boolean nonVirtual = false; // nonVirtual |= call instanceof Call && ((Call) call).nonVirtual(); // is this really used // TODO rewrite non-virtual call with super bridge call // nonVirtual |= call.target() instanceof Special && ((Special) call.target()).kind() == Special.SUPER; // TODO rewrite non-virtual call with super bridge call // nonVirtual |= call instanceof ConstructorCall && ((ConstructorCall) call).kind() == ConstructorCall.SUPER; // TODO rewrite non-virtual call with super bridge call if (pkg==null) return null; if (!nonVirtual && !pkg.inlinable) return null; boolean required = utils.inliningRequired(call) || utils.inliningRequired(def); ProcedureDecl decl = pkg.getDecl(required ? Integer.MAX_VALUE : implicitMax, !nonVirtual); return decl; } /** * @param call * @return */ X10ProcedureDef getDef(InlinableCall call) { if (call instanceof Call) { return (X10ProcedureDef) ((Call) call).methodInstance().def(); } if (call instanceof ConstructorCall) { return (X10ProcedureDef) ((ConstructorCall) call).constructorInstance().def(); } if (call instanceof ClosureCall) { return (X10ProcedureDef) ((ClosureCall) call).closureInstance().def(); } return null; } /** * @param def * @return */ DeclPackage getDeclPackage(X10ProcedureDef def) { if (Position.COMPILER_GENERATED == def.position()) return ambiguousDef; return declPackages.get(cannonize(def)); } /** * @param def * @param pkg */ void putDeclPackage(X10ProcedureDef def, DeclPackage pkg) { declPackages.put(cannonize(def), pkg); } /** * @param def * @return */ private String cannonize(X10ProcedureDef def) { return (def.position().nameAndLineString()+ ": " +def.signature()).intern(); } }