src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Splitter.java

Print this page




  25 
  26 package jdk.nashorn.internal.codegen;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
  29 
  30 import java.util.ArrayList;
  31 import java.util.HashMap;
  32 import java.util.List;
  33 import java.util.Map;
  34 import jdk.nashorn.internal.ir.Block;
  35 import jdk.nashorn.internal.ir.FunctionNode;
  36 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
  37 import jdk.nashorn.internal.ir.LexicalContext;
  38 import jdk.nashorn.internal.ir.LiteralNode;
  39 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
  40 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
  41 import jdk.nashorn.internal.ir.Node;
  42 import jdk.nashorn.internal.ir.SplitNode;
  43 import jdk.nashorn.internal.ir.Statement;
  44 import jdk.nashorn.internal.ir.visitor.NodeVisitor;

  45 import jdk.nashorn.internal.runtime.logging.DebugLogger;


  46 import jdk.nashorn.internal.runtime.options.Options;
  47 
  48 /**
  49  * Split the IR into smaller compile units.
  50  */
  51 final class Splitter extends NodeVisitor<LexicalContext> {

  52     /** Current compiler. */
  53     private final Compiler compiler;
  54 
  55     /** IR to be broken down. */
  56     private final FunctionNode outermost;
  57 
  58     /** Compile unit for the main script. */
  59     private final CompileUnit outermostCompileUnit;
  60 
  61     /** Cache for calculated block weights. */
  62     private final Map<Node, Long> weightCache = new HashMap<>();
  63 
  64     /** Weight threshold for when to start a split. */
  65     public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
  66 
  67     private final DebugLogger log;
  68 
  69     /**
  70      * Constructor.
  71      *
  72      * @param compiler              the compiler
  73      * @param functionNode          function node to split
  74      * @param outermostCompileUnit  compile unit for outermost function, if non-lazy this is the script's compile unit
  75      */
  76     public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
  77         super(new LexicalContext());
  78         this.compiler             = compiler;
  79         this.outermost            = functionNode;
  80         this.outermostCompileUnit = outermostCompileUnit;
  81         this.log                  = compiler.getLogger();










  82     }
  83 
  84     /**
  85      * Execute the split.
  86      * @param fn the function to split
  87      * @param top whether this is the topmost compiled function (it's either a program, or we're doing a recompilation).
  88      */
  89     FunctionNode split(final FunctionNode fn, final boolean top) {
  90         FunctionNode functionNode = fn;
  91 
  92         log.finest("Initiating split of '", functionNode.getName(), "'");
  93 
  94         long weight = WeighNodes.weigh(functionNode);
  95 
  96         // We know that our LexicalContext is empty outside the call to functionNode.accept(this) below,
  97         // so we can pass null to all methods expecting a LexicalContext parameter.
  98         assert lc.isEmpty() : "LexicalContext not empty";
  99 
 100         if (weight >= SPLIT_THRESHOLD) {
 101             log.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
 102             functionNode = (FunctionNode)functionNode.accept(this);
 103 
 104             if (functionNode.isSplit()) {
 105                 // Weight has changed so weigh again, this time using block weight cache
 106                 weight = WeighNodes.weigh(functionNode, weightCache);
 107                 functionNode = functionNode.setBody(null, functionNode.getBody().setNeedsScope(null));
 108             }
 109 
 110             if (weight >= SPLIT_THRESHOLD) {
 111                 functionNode = functionNode.setBody(null, splitBlock(functionNode.getBody(), functionNode));
 112                 functionNode = functionNode.setFlag(null, FunctionNode.IS_SPLIT);
 113                 weight = WeighNodes.weigh(functionNode.getBody(), weightCache);
 114             }
 115         }
 116 
 117         assert functionNode.getCompileUnit() == null : "compile unit already set for " + functionNode.getName();
 118 
 119         if (top) {
 120             assert outermostCompileUnit != null : "outermost compile unit is null";
 121             functionNode = functionNode.setCompileUnit(null, outermostCompileUnit);




  25 
  26 package jdk.nashorn.internal.codegen;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
  29 
  30 import java.util.ArrayList;
  31 import java.util.HashMap;
  32 import java.util.List;
  33 import java.util.Map;
  34 import jdk.nashorn.internal.ir.Block;
  35 import jdk.nashorn.internal.ir.FunctionNode;
  36 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
  37 import jdk.nashorn.internal.ir.LexicalContext;
  38 import jdk.nashorn.internal.ir.LiteralNode;
  39 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
  40 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
  41 import jdk.nashorn.internal.ir.Node;
  42 import jdk.nashorn.internal.ir.SplitNode;
  43 import jdk.nashorn.internal.ir.Statement;
  44 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
  45 import jdk.nashorn.internal.runtime.Context;
  46 import jdk.nashorn.internal.runtime.logging.DebugLogger;
  47 import jdk.nashorn.internal.runtime.logging.Loggable;
  48 import jdk.nashorn.internal.runtime.logging.Logger;
  49 import jdk.nashorn.internal.runtime.options.Options;
  50 
  51 /**
  52  * Split the IR into smaller compile units.
  53  */
  54 @Logger(name="splitter")
  55 final class Splitter extends NodeVisitor<LexicalContext> implements Loggable {
  56     /** Current compiler. */
  57     private final Compiler compiler;
  58 
  59     /** IR to be broken down. */
  60     private final FunctionNode outermost;
  61 
  62     /** Compile unit for the main script. */
  63     private final CompileUnit outermostCompileUnit;
  64 
  65     /** Cache for calculated block weights. */
  66     private final Map<Node, Long> weightCache = new HashMap<>();
  67 
  68     /** Weight threshold for when to start a split. */
  69     public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
  70 
  71     private final DebugLogger log;
  72 
  73     /**
  74      * Constructor.
  75      *
  76      * @param compiler              the compiler
  77      * @param functionNode          function node to split
  78      * @param outermostCompileUnit  compile unit for outermost function, if non-lazy this is the script's compile unit
  79      */
  80     public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
  81         super(new LexicalContext());
  82         this.compiler             = compiler;
  83         this.outermost            = functionNode;
  84         this.outermostCompileUnit = outermostCompileUnit;
  85         this.log                  = initLogger(compiler.getContext());
  86     }
  87 
  88     @Override
  89     public DebugLogger initLogger(final Context context) {
  90         return context.getLogger(this.getClass());
  91     }
  92 
  93     @Override
  94     public DebugLogger getLogger() {
  95         return log;
  96     }
  97 
  98     /**
  99      * Execute the split.
 100      * @param fn the function to split
 101      * @param top whether this is the topmost compiled function (it's either a program, or we're doing a recompilation).
 102      */
 103     FunctionNode split(final FunctionNode fn, final boolean top) {
 104         FunctionNode functionNode = fn;
 105 
 106         log.fine("Initiating split of '", functionNode.getName(), "'");
 107 
 108         long weight = WeighNodes.weigh(functionNode);
 109 
 110         // We know that our LexicalContext is empty outside the call to functionNode.accept(this) below,
 111         // so we can pass null to all methods expecting a LexicalContext parameter.
 112         assert lc.isEmpty() : "LexicalContext not empty";
 113 
 114         if (weight >= SPLIT_THRESHOLD) {
 115             log.info("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
 116             functionNode = (FunctionNode)functionNode.accept(this);
 117 
 118             if (functionNode.isSplit()) {
 119                 // Weight has changed so weigh again, this time using block weight cache
 120                 weight = WeighNodes.weigh(functionNode, weightCache);
 121                 functionNode = functionNode.setBody(null, functionNode.getBody().setNeedsScope(null));
 122             }
 123 
 124             if (weight >= SPLIT_THRESHOLD) {
 125                 functionNode = functionNode.setBody(null, splitBlock(functionNode.getBody(), functionNode));
 126                 functionNode = functionNode.setFlag(null, FunctionNode.IS_SPLIT);
 127                 weight = WeighNodes.weigh(functionNode.getBody(), weightCache);
 128             }
 129         }
 130 
 131         assert functionNode.getCompileUnit() == null : "compile unit already set for " + functionNode.getName();
 132 
 133         if (top) {
 134             assert outermostCompileUnit != null : "outermost compile unit is null";
 135             functionNode = functionNode.setCompileUnit(null, outermostCompileUnit);