47 import jdk.nashorn.internal.runtime.options.Options; |
47 import jdk.nashorn.internal.runtime.options.Options; |
48 |
48 |
49 /** |
49 /** |
50 * Split the IR into smaller compile units. |
50 * Split the IR into smaller compile units. |
51 */ |
51 */ |
52 final class Splitter extends NodeVisitor { |
52 final class Splitter extends NodeVisitor<LexicalContext> { |
53 /** Current compiler. */ |
53 /** Current compiler. */ |
54 private final Compiler compiler; |
54 private final Compiler compiler; |
55 |
55 |
56 /** IR to be broken down. */ |
56 /** IR to be broken down. */ |
57 private FunctionNode outermost; |
57 private final FunctionNode outermost; |
58 |
58 |
59 /** Compile unit for the main script. */ |
59 /** Compile unit for the main script. */ |
60 private final CompileUnit outermostCompileUnit; |
60 private final CompileUnit outermostCompileUnit; |
61 |
61 |
62 /** Cache for calculated block weights. */ |
62 /** Cache for calculated block weights. */ |
73 * @param compiler the compiler |
73 * @param compiler the compiler |
74 * @param functionNode function node to split |
74 * @param functionNode function node to split |
75 * @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit |
75 * @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit |
76 */ |
76 */ |
77 public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { |
77 public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { |
|
78 super(new LexicalContext()); |
78 this.compiler = compiler; |
79 this.compiler = compiler; |
79 this.outermost = functionNode; |
80 this.outermost = functionNode; |
80 this.outermostCompileUnit = outermostCompileUnit; |
81 this.outermostCompileUnit = outermostCompileUnit; |
81 } |
82 } |
82 |
83 |
90 LOG.finest("Postponing split of '", functionNode.getName(), "' as it's lazy"); |
91 LOG.finest("Postponing split of '", functionNode.getName(), "' as it's lazy"); |
91 return functionNode; |
92 return functionNode; |
92 } |
93 } |
93 |
94 |
94 LOG.finest("Initiating split of '", functionNode.getName(), "'"); |
95 LOG.finest("Initiating split of '", functionNode.getName(), "'"); |
95 |
|
96 final LexicalContext lc = getLexicalContext(); |
|
97 |
96 |
98 long weight = WeighNodes.weigh(functionNode); |
97 long weight = WeighNodes.weigh(functionNode); |
99 final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost; |
98 final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost; |
100 |
99 |
101 if (weight >= SPLIT_THRESHOLD) { |
100 if (weight >= SPLIT_THRESHOLD) { |
125 } |
124 } |
126 |
125 |
127 final Block body = functionNode.getBody(); |
126 final Block body = functionNode.getBody(); |
128 final List<FunctionNode> dc = directChildren(functionNode); |
127 final List<FunctionNode> dc = directChildren(functionNode); |
129 |
128 |
130 final Block newBody = (Block)body.accept(new NodeVisitor() { |
129 final Block newBody = (Block)body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
131 @Override |
130 @Override |
132 public boolean enterFunctionNode(final FunctionNode nestedFunction) { |
131 public boolean enterFunctionNode(final FunctionNode nestedFunction) { |
133 return dc.contains(nestedFunction); |
132 return dc.contains(nestedFunction); |
134 } |
133 } |
135 |
134 |
136 @Override |
135 @Override |
137 public Node leaveFunctionNode(final FunctionNode nestedFunction) { |
136 public Node leaveFunctionNode(final FunctionNode nestedFunction) { |
138 FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction); |
137 FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction); |
139 getLexicalContext().replace(nestedFunction, split); |
138 lc.replace(nestedFunction, split); |
140 return split; |
139 return split; |
141 } |
140 } |
142 }); |
141 }); |
143 functionNode = functionNode.setBody(lc, newBody); |
142 functionNode = functionNode.setBody(lc, newBody); |
144 |
143 |
147 return functionNode.setState(lc, CompilationState.SPLIT); |
146 return functionNode.setState(lc, CompilationState.SPLIT); |
148 } |
147 } |
149 |
148 |
150 private static List<FunctionNode> directChildren(final FunctionNode functionNode) { |
149 private static List<FunctionNode> directChildren(final FunctionNode functionNode) { |
151 final List<FunctionNode> dc = new ArrayList<>(); |
150 final List<FunctionNode> dc = new ArrayList<>(); |
152 functionNode.accept(new NodeVisitor() { |
151 functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { |
153 @Override |
152 @Override |
154 public boolean enterFunctionNode(final FunctionNode child) { |
153 public boolean enterFunctionNode(final FunctionNode child) { |
155 if (child == functionNode) { |
154 if (child == functionNode) { |
156 return true; |
155 return true; |
157 } |
156 } |
158 if (getLexicalContext().getParentFunction(child) == functionNode) { |
157 if (lc.getParentFunction(child) == functionNode) { |
159 dc.add(child); |
158 dc.add(child); |
160 } |
159 } |
161 return false; |
160 return false; |
162 } |
161 } |
163 }); |
162 }); |
179 * @param block Block or function to split. |
178 * @param block Block or function to split. |
180 * |
179 * |
181 * @return new weight for the resulting block. |
180 * @return new weight for the resulting block. |
182 */ |
181 */ |
183 private Block splitBlock(final Block block, final FunctionNode function) { |
182 private Block splitBlock(final Block block, final FunctionNode function) { |
184 getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); |
183 lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_SPLIT); |
185 |
184 |
186 final List<Statement> splits = new ArrayList<>(); |
185 final List<Statement> splits = new ArrayList<>(); |
187 List<Statement> statements = new ArrayList<>(); |
186 List<Statement> statements = new ArrayList<>(); |
188 long statementsWeight = 0; |
187 long statementsWeight = 0; |
189 |
188 |
208 |
207 |
209 if (!statements.isEmpty()) { |
208 if (!statements.isEmpty()) { |
210 splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); |
209 splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); |
211 } |
210 } |
212 |
211 |
213 return block.setStatements(getLexicalContext(), splits); |
212 return block.setStatements(lc, splits); |
214 } |
213 } |
215 |
214 |
216 /** |
215 /** |
217 * Create a new split node from statements contained in a parent block. |
216 * Create a new split node from statements contained in a parent block. |
218 * |
217 * |
256 |
255 |
257 // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have |
256 // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have |
258 // been split already, so weigh again before splitting. |
257 // been split already, so weigh again before splitting. |
259 long weight = WeighNodes.weigh(block, weightCache); |
258 long weight = WeighNodes.weigh(block, weightCache); |
260 if (weight >= SPLIT_THRESHOLD) { |
259 if (weight >= SPLIT_THRESHOLD) { |
261 newBlock = splitBlock(block, getLexicalContext().getFunction(block)); |
260 newBlock = splitBlock(block, lc.getFunction(block)); |
262 weight = WeighNodes.weigh(newBlock, weightCache); |
261 weight = WeighNodes.weigh(newBlock, weightCache); |
263 } |
262 } |
264 weightCache.put(newBlock, weight); |
263 weightCache.put(newBlock, weight); |
265 return newBlock; |
264 return newBlock; |
266 } |
265 } |
272 |
271 |
273 if (weight < SPLIT_THRESHOLD) { |
272 if (weight < SPLIT_THRESHOLD) { |
274 return literal; |
273 return literal; |
275 } |
274 } |
276 |
275 |
277 final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); |
276 final FunctionNode functionNode = lc.getCurrentFunction(); |
278 |
277 |
279 getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT); |
278 lc.setFlag(functionNode, FunctionNode.IS_SPLIT); |
280 |
279 |
281 if (literal instanceof ArrayLiteralNode) { |
280 if (literal instanceof ArrayLiteralNode) { |
282 final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal; |
281 final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal; |
283 final Node[] value = arrayLiteralNode.getValue(); |
282 final Node[] value = arrayLiteralNode.getValue(); |
284 final int[] postsets = arrayLiteralNode.getPostsets(); |
283 final int[] postsets = arrayLiteralNode.getPostsets(); |