WeighNodes.java revision 1966:6ac0ca441ccb
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.codegen;
27
28import java.util.List;
29import java.util.Map;
30import jdk.nashorn.internal.ir.AccessNode;
31import jdk.nashorn.internal.ir.BinaryNode;
32import jdk.nashorn.internal.ir.Block;
33import jdk.nashorn.internal.ir.BreakNode;
34import jdk.nashorn.internal.ir.CallNode;
35import jdk.nashorn.internal.ir.CatchNode;
36import jdk.nashorn.internal.ir.ContinueNode;
37import jdk.nashorn.internal.ir.ExpressionStatement;
38import jdk.nashorn.internal.ir.ForNode;
39import jdk.nashorn.internal.ir.FunctionNode;
40import jdk.nashorn.internal.ir.IdentNode;
41import jdk.nashorn.internal.ir.IfNode;
42import jdk.nashorn.internal.ir.IndexNode;
43import jdk.nashorn.internal.ir.JumpToInlinedFinally;
44import jdk.nashorn.internal.ir.LexicalContext;
45import jdk.nashorn.internal.ir.LiteralNode;
46import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
47import jdk.nashorn.internal.ir.Node;
48import jdk.nashorn.internal.ir.ObjectNode;
49import jdk.nashorn.internal.ir.PropertyNode;
50import jdk.nashorn.internal.ir.ReturnNode;
51import jdk.nashorn.internal.ir.RuntimeNode;
52import jdk.nashorn.internal.ir.SplitNode;
53import jdk.nashorn.internal.ir.Splittable;
54import jdk.nashorn.internal.ir.SwitchNode;
55import jdk.nashorn.internal.ir.ThrowNode;
56import jdk.nashorn.internal.ir.TryNode;
57import jdk.nashorn.internal.ir.UnaryNode;
58import jdk.nashorn.internal.ir.VarNode;
59import jdk.nashorn.internal.ir.WhileNode;
60import jdk.nashorn.internal.ir.WithNode;
61import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
62
63
64/**
65 * Computes the "byte code" weight of an AST segment. This is used
66 * for Splitting too large class files
67 */
68final class WeighNodes extends NodeOperatorVisitor<LexicalContext> {
69    /*
70     * Weight constants.
71     */
72    static final long FUNCTION_WEIGHT  = 40;
73    static final long AASTORE_WEIGHT   =  2;
74    static final long ACCESS_WEIGHT    =  4;
75    static final long ADD_WEIGHT       = 10;
76    static final long BREAK_WEIGHT     =  1;
77    static final long CALL_WEIGHT      = 10;
78    static final long CATCH_WEIGHT     = 10;
79    static final long COMPARE_WEIGHT   =  6;
80    static final long CONTINUE_WEIGHT  =  1;
81    static final long IF_WEIGHT        =  2;
82    static final long LITERAL_WEIGHT   = 10;
83    static final long LOOP_WEIGHT      =  4;
84    static final long NEW_WEIGHT       =  6;
85    static final long FUNC_EXPR_WEIGHT = 20;
86    static final long RETURN_WEIGHT    =  2;
87    static final long SPLIT_WEIGHT     = 40;
88    static final long SWITCH_WEIGHT    =  8;
89    static final long THROW_WEIGHT     =  2;
90    static final long VAR_WEIGHT       = 40;
91    static final long WITH_WEIGHT      =  8;
92    static final long OBJECT_WEIGHT    = 16;
93    static final long SETPROP_WEIGHT   =  5;
94
95    /** Accumulated weight. */
96    private long weight;
97
98    /** Optional cache for weight of block nodes. */
99    private final Map<Node, Long> weightCache;
100
101    private final FunctionNode topFunction;
102
103    /**
104     * Constructor
105     *
106     * @param weightCache cache of already calculated block weights
107     */
108    private WeighNodes(final FunctionNode topFunction, final Map<Node, Long> weightCache) {
109        super(new LexicalContext());
110        this.topFunction = topFunction;
111        this.weightCache = weightCache;
112    }
113
114    static long weigh(final Node node) {
115        return weigh(node, null);
116    }
117
118    static long weigh(final Node node, final Map<Node, Long> weightCache) {
119        final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache);
120        node.accept(weighNodes);
121        return weighNodes.weight;
122    }
123
124    @Override
125    public Node leaveAccessNode(final AccessNode accessNode) {
126        weight += ACCESS_WEIGHT;
127        return accessNode;
128    }
129
130    @Override
131    public boolean enterBlock(final Block block) {
132        if (weightCache != null && weightCache.containsKey(block)) {
133            weight += weightCache.get(block);
134            return false;
135        }
136
137        return true;
138    }
139
140    @Override
141    public Node leaveBreakNode(final BreakNode breakNode) {
142        weight += BREAK_WEIGHT;
143        return breakNode;
144    }
145
146    @Override
147    public Node leaveCallNode(final CallNode callNode) {
148        weight += CALL_WEIGHT;
149        return callNode;
150    }
151
152    @Override
153    public Node leaveCatchNode(final CatchNode catchNode) {
154        weight += CATCH_WEIGHT;
155        return catchNode;
156    }
157
158    @Override
159    public Node leaveContinueNode(final ContinueNode continueNode) {
160        weight += CONTINUE_WEIGHT;
161        return continueNode;
162    }
163
164    @Override
165    public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
166        return expressionStatement;
167    }
168
169    @Override
170    public Node leaveForNode(final ForNode forNode) {
171        weight += LOOP_WEIGHT;
172        return forNode;
173    }
174
175    @Override
176    public boolean enterFunctionNode(final FunctionNode functionNode) {
177        if (functionNode == topFunction) {
178            // the function being weighted; descend into its statements
179            return true;
180        }
181        // just a reference to inner function from outer function
182        weight += FUNC_EXPR_WEIGHT;
183        return false;
184    }
185
186    @Override
187    public Node leaveIdentNode(final IdentNode identNode) {
188        weight += ACCESS_WEIGHT;
189        return identNode;
190    }
191
192    @Override
193    public Node leaveIfNode(final IfNode ifNode) {
194        weight += IF_WEIGHT;
195        return ifNode;
196    }
197
198    @Override
199    public Node leaveIndexNode(final IndexNode indexNode) {
200        weight += ACCESS_WEIGHT;
201        return indexNode;
202    }
203
204    @Override
205    public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
206        weight += BREAK_WEIGHT;
207        return jumpToInlinedFinally;
208    }
209
210    @SuppressWarnings("rawtypes")
211    @Override
212    public boolean enterLiteralNode(final LiteralNode literalNode) {
213        weight += LITERAL_WEIGHT;
214
215        if (literalNode instanceof ArrayLiteralNode) {
216            final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
217            final Node[]           value            = arrayLiteralNode.getValue();
218            final int[]            postsets         = arrayLiteralNode.getPostsets();
219            final List<Splittable.SplitRange>  units            = arrayLiteralNode.getSplitRanges();
220
221            if (units == null) {
222                for (final int postset : postsets) {
223                    weight += AASTORE_WEIGHT;
224                    final Node element = value[postset];
225
226                    if (element != null) {
227                        element.accept(this);
228                    }
229                }
230            }
231
232            return false;
233        }
234
235        return true;
236    }
237
238    @Override
239    public boolean enterObjectNode(final ObjectNode objectNode) {
240        weight += OBJECT_WEIGHT;
241        final List<PropertyNode> properties = objectNode.getElements();
242        final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
243
244        for (final PropertyNode property : properties) {
245            if (!LiteralNode.isConstant(property.getValue())) {
246                weight += SETPROP_WEIGHT;
247                property.getValue().accept(this);
248            } else if (!isSpillObject) {
249                // constants in spill object are set via preset spill array,
250                // but fields objects need to set constants.
251                weight += SETPROP_WEIGHT;
252            }
253
254        }
255
256        return false;
257    }
258
259    @Override
260    public Node leavePropertyNode(final PropertyNode propertyNode) {
261        weight += LITERAL_WEIGHT;
262        return propertyNode;
263    }
264
265    @Override
266    public Node leaveReturnNode(final ReturnNode returnNode) {
267        weight += RETURN_WEIGHT;
268        return returnNode;
269    }
270
271    @Override
272    public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
273        weight += CALL_WEIGHT;
274        return runtimeNode;
275    }
276
277    @Override
278    public boolean enterSplitNode(final SplitNode splitNode) {
279        weight += SPLIT_WEIGHT;
280        return false;
281    }
282
283    @Override
284    public Node leaveSwitchNode(final SwitchNode switchNode) {
285        weight += SWITCH_WEIGHT;
286        return switchNode;
287    }
288
289    @Override
290    public Node leaveThrowNode(final ThrowNode throwNode) {
291        weight += THROW_WEIGHT;
292        return throwNode;
293    }
294
295    @Override
296    public Node leaveTryNode(final TryNode tryNode) {
297        weight += THROW_WEIGHT;
298        return tryNode;
299    }
300
301    @Override
302    public Node leaveVarNode(final VarNode varNode) {
303        weight += VAR_WEIGHT;
304        return varNode;
305    }
306
307    @Override
308    public Node leaveWhileNode(final WhileNode whileNode) {
309        weight += LOOP_WEIGHT;
310        return whileNode;
311    }
312
313    @Override
314    public Node leaveWithNode(final WithNode withNode) {
315        weight += WITH_WEIGHT;
316        return withNode;
317    }
318
319    @Override
320    public Node leaveADD(final UnaryNode unaryNode) {
321        return unaryNodeWeight(unaryNode);
322    }
323
324    @Override
325    public Node leaveBIT_NOT(final UnaryNode unaryNode) {
326        return unaryNodeWeight(unaryNode);
327    }
328
329    @Override
330    public Node leaveDECINC(final UnaryNode unaryNode) {
331         return unaryNodeWeight(unaryNode);
332    }
333
334    @Override
335    public Node leaveDELETE(final UnaryNode unaryNode) {
336        return runtimeNodeWeight(unaryNode);
337    }
338
339    @Override
340    public Node leaveNEW(final UnaryNode unaryNode) {
341        weight += NEW_WEIGHT;
342        return unaryNode;
343    }
344
345    @Override
346    public Node leaveNOT(final UnaryNode unaryNode) {
347        return unaryNodeWeight(unaryNode);
348    }
349
350    @Override
351    public Node leaveSUB(final UnaryNode unaryNode) {
352        return unaryNodeWeight(unaryNode);
353    }
354
355    @Override
356    public Node leaveTYPEOF(final UnaryNode unaryNode) {
357        return runtimeNodeWeight(unaryNode);
358    }
359
360    @Override
361    public Node leaveVOID(final UnaryNode unaryNode) {
362        return unaryNodeWeight(unaryNode);
363    }
364
365    @Override
366    public Node leaveADD(final BinaryNode binaryNode) {
367        weight += ADD_WEIGHT;
368        return binaryNode;
369    }
370
371    @Override
372    public Node leaveAND(final BinaryNode binaryNode) {
373        return binaryNodeWeight(binaryNode);
374    }
375
376    @Override
377    public Node leaveASSIGN(final BinaryNode binaryNode) {
378        return binaryNodeWeight(binaryNode);
379    }
380
381    @Override
382    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
383        weight += ADD_WEIGHT;
384        return binaryNode;
385    }
386
387    @Override
388    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
389        return binaryNodeWeight(binaryNode);
390    }
391
392    @Override
393    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
394        return binaryNodeWeight(binaryNode);
395    }
396
397    @Override
398    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
399        return binaryNodeWeight(binaryNode);
400    }
401
402    @Override
403    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
404        return binaryNodeWeight(binaryNode);
405    }
406
407    @Override
408    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
409        return binaryNodeWeight(binaryNode);
410    }
411
412    @Override
413    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
414        return binaryNodeWeight(binaryNode);
415    }
416
417    @Override
418    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
419        return binaryNodeWeight(binaryNode);
420    }
421
422    @Override
423    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
424        return binaryNodeWeight(binaryNode);
425    }
426
427    @Override
428    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
429        return binaryNodeWeight(binaryNode);
430    }
431
432    @Override
433    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
434        return binaryNodeWeight(binaryNode);
435    }
436
437    @Override
438    public Node leaveARROW(final BinaryNode binaryNode) {
439        return binaryNodeWeight(binaryNode);
440    }
441
442    @Override
443    public Node leaveBIT_AND(final BinaryNode binaryNode) {
444        return binaryNodeWeight(binaryNode);
445    }
446
447    @Override
448    public Node leaveBIT_OR(final BinaryNode binaryNode) {
449        return binaryNodeWeight(binaryNode);
450    }
451
452    @Override
453    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
454        return binaryNodeWeight(binaryNode);
455    }
456
457    @Override
458    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
459        return binaryNodeWeight(binaryNode);
460    }
461
462    @Override
463    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
464        return binaryNodeWeight(binaryNode);
465    }
466
467    @Override
468    public Node leaveDIV(final BinaryNode binaryNode) {
469        return binaryNodeWeight(binaryNode);
470    }
471
472    @Override
473    public Node leaveEQ(final BinaryNode binaryNode) {
474        return compareWeight(binaryNode);
475    }
476
477    @Override
478    public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
479        return compareWeight(binaryNode);
480    }
481
482    @Override
483    public Node leaveGE(final BinaryNode binaryNode) {
484        return compareWeight(binaryNode);
485    }
486
487    @Override
488    public Node leaveGT(final BinaryNode binaryNode) {
489        return compareWeight(binaryNode);
490    }
491
492    @Override
493    public Node leaveIN(final BinaryNode binaryNode) {
494        weight += CALL_WEIGHT;
495        return binaryNode;
496    }
497
498    @Override
499    public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
500        weight += CALL_WEIGHT;
501        return binaryNode;
502    }
503
504    @Override
505    public Node leaveLE(final BinaryNode binaryNode) {
506        return compareWeight(binaryNode);
507    }
508
509    @Override
510    public Node leaveLT(final BinaryNode binaryNode) {
511        return compareWeight(binaryNode);
512    }
513
514    @Override
515    public Node leaveMOD(final BinaryNode binaryNode) {
516        return binaryNodeWeight(binaryNode);
517    }
518
519    @Override
520    public Node leaveMUL(final BinaryNode binaryNode) {
521        return binaryNodeWeight(binaryNode);
522    }
523
524    @Override
525    public Node leaveNE(final BinaryNode binaryNode) {
526        return compareWeight(binaryNode);
527    }
528
529    @Override
530    public Node leaveNE_STRICT(final BinaryNode binaryNode) {
531        return compareWeight(binaryNode);
532    }
533
534    @Override
535    public Node leaveOR(final BinaryNode binaryNode) {
536        return binaryNodeWeight(binaryNode);
537    }
538
539    @Override
540    public Node leaveSAR(final BinaryNode binaryNode) {
541        return binaryNodeWeight(binaryNode);
542    }
543
544    @Override
545    public Node leaveSHL(final BinaryNode binaryNode) {
546        return binaryNodeWeight(binaryNode);
547    }
548
549    @Override
550    public Node leaveSHR(final BinaryNode binaryNode) {
551        return binaryNodeWeight(binaryNode);
552    }
553
554    @Override
555    public Node leaveSUB(final BinaryNode binaryNode) {
556        return binaryNodeWeight(binaryNode);
557    }
558
559    private Node unaryNodeWeight(final UnaryNode unaryNode) {
560        weight += 1;
561        return unaryNode;
562    }
563
564    private Node binaryNodeWeight(final BinaryNode binaryNode) {
565        weight += 1;
566        return binaryNode;
567    }
568
569    private Node runtimeNodeWeight(final UnaryNode unaryNode) {
570        weight += CALL_WEIGHT;
571        return unaryNode;
572    }
573
574    private Node compareWeight(final BinaryNode binaryNode) {
575        weight += COMPARE_WEIGHT;
576        return binaryNode;
577    }
578}
579