WeighNodes.java revision 1875:ea1d4ecf5862
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 CONST_WEIGHT     =  2;
81    static final long CONTINUE_WEIGHT  =  1;
82    static final long IF_WEIGHT        =  2;
83    static final long LITERAL_WEIGHT   = 10;
84    static final long LOOP_WEIGHT      =  4;
85    static final long NEW_WEIGHT       =  6;
86    static final long FUNC_EXPR_WEIGHT = 20;
87    static final long RETURN_WEIGHT    =  2;
88    static final long SPLIT_WEIGHT     = 40;
89    static final long SWITCH_WEIGHT    =  8;
90    static final long THROW_WEIGHT     =  2;
91    static final long VAR_WEIGHT       = 40;
92    static final long WITH_WEIGHT      =  8;
93    static final long OBJECT_WEIGHT    = 16;
94    static final long SETPROP_WEIGHT   =  5;
95
96    /** Accumulated weight. */
97    private long weight;
98
99    /** Optional cache for weight of block nodes. */
100    private final Map<Node, Long> weightCache;
101
102    private final FunctionNode topFunction;
103
104    /**
105     * Constructor
106     *
107     * @param weightCache cache of already calculated block weights
108     */
109    private WeighNodes(final FunctionNode topFunction, final Map<Node, Long> weightCache) {
110        super(new LexicalContext());
111        this.topFunction = topFunction;
112        this.weightCache = weightCache;
113    }
114
115    static long weigh(final Node node) {
116        return weigh(node, null);
117    }
118
119    static long weigh(final Node node, final Map<Node, Long> weightCache) {
120        final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache);
121        node.accept(weighNodes);
122        return weighNodes.weight;
123    }
124
125    @Override
126    public Node leaveAccessNode(final AccessNode accessNode) {
127        weight += ACCESS_WEIGHT;
128        return accessNode;
129    }
130
131    @Override
132    public boolean enterBlock(final Block block) {
133        if (weightCache != null && weightCache.containsKey(block)) {
134            weight += weightCache.get(block);
135            return false;
136        }
137
138        return true;
139    }
140
141    @Override
142    public Node leaveBreakNode(final BreakNode breakNode) {
143        weight += BREAK_WEIGHT;
144        return breakNode;
145    }
146
147    @Override
148    public Node leaveCallNode(final CallNode callNode) {
149        weight += CALL_WEIGHT;
150        return callNode;
151    }
152
153    @Override
154    public Node leaveCatchNode(final CatchNode catchNode) {
155        weight += CATCH_WEIGHT;
156        return catchNode;
157    }
158
159    @Override
160    public Node leaveContinueNode(final ContinueNode continueNode) {
161        weight += CONTINUE_WEIGHT;
162        return continueNode;
163    }
164
165    @Override
166    public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
167        return expressionStatement;
168    }
169
170    @Override
171    public Node leaveForNode(final ForNode forNode) {
172        weight += LOOP_WEIGHT;
173        return forNode;
174    }
175
176    @Override
177    public boolean enterFunctionNode(final FunctionNode functionNode) {
178        if (functionNode == topFunction) {
179            // the function being weighted; descend into its statements
180            return true;
181        }
182        // just a reference to inner function from outer function
183        weight += FUNC_EXPR_WEIGHT;
184        return false;
185    }
186
187    @Override
188    public Node leaveIdentNode(final IdentNode identNode) {
189        weight += ACCESS_WEIGHT;
190        return identNode;
191    }
192
193    @Override
194    public Node leaveIfNode(final IfNode ifNode) {
195        weight += IF_WEIGHT;
196        return ifNode;
197    }
198
199    @Override
200    public Node leaveIndexNode(final IndexNode indexNode) {
201        weight += ACCESS_WEIGHT;
202        return indexNode;
203    }
204
205    @Override
206    public Node leaveJumpToInlinedFinally(final JumpToInlinedFinally jumpToInlinedFinally) {
207        weight += BREAK_WEIGHT;
208        return jumpToInlinedFinally;
209    }
210
211    @SuppressWarnings("rawtypes")
212    @Override
213    public boolean enterLiteralNode(final LiteralNode literalNode) {
214        if (literalNode instanceof LiteralNode.PrimitiveLiteralNode) {
215            weight += CONST_WEIGHT;
216            return false;
217        }
218
219        weight += LITERAL_WEIGHT;
220
221        if (literalNode instanceof ArrayLiteralNode) {
222            final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
223            final Node[]           value            = arrayLiteralNode.getValue();
224            final int[]            postsets         = arrayLiteralNode.getPostsets();
225            final List<Splittable.SplitRange>  units            = arrayLiteralNode.getSplitRanges();
226
227            if (units == null) {
228                for (final int postset : postsets) {
229                    weight += AASTORE_WEIGHT;
230                    final Node element = value[postset];
231
232                    if (element != null) {
233                        element.accept(this);
234                    }
235                }
236            }
237
238            return false;
239        }
240
241        return true;
242    }
243
244    @Override
245    public boolean enterObjectNode(final ObjectNode objectNode) {
246        weight += OBJECT_WEIGHT;
247        final List<PropertyNode> properties = objectNode.getElements();
248        final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
249
250        for (final PropertyNode property : properties) {
251            if (!LiteralNode.isConstant(property.getValue())) {
252                weight += SETPROP_WEIGHT;
253                property.getValue().accept(this);
254            } else if (!isSpillObject) {
255                // constants in spill object are set via preset spill array,
256                // but fields objects need to set constants.
257                weight += SETPROP_WEIGHT;
258            }
259
260        }
261
262        return false;
263    }
264
265    @Override
266    public Node leavePropertyNode(final PropertyNode propertyNode) {
267        weight += LITERAL_WEIGHT;
268        return propertyNode;
269    }
270
271    @Override
272    public Node leaveReturnNode(final ReturnNode returnNode) {
273        weight += RETURN_WEIGHT;
274        return returnNode;
275    }
276
277    @Override
278    public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
279        weight += CALL_WEIGHT;
280        return runtimeNode;
281    }
282
283    @Override
284    public boolean enterSplitNode(final SplitNode splitNode) {
285        weight += SPLIT_WEIGHT;
286        return false;
287    }
288
289    @Override
290    public Node leaveSwitchNode(final SwitchNode switchNode) {
291        weight += SWITCH_WEIGHT;
292        return switchNode;
293    }
294
295    @Override
296    public Node leaveThrowNode(final ThrowNode throwNode) {
297        weight += THROW_WEIGHT;
298        return throwNode;
299    }
300
301    @Override
302    public Node leaveTryNode(final TryNode tryNode) {
303        weight += THROW_WEIGHT;
304        return tryNode;
305    }
306
307    @Override
308    public Node leaveVarNode(final VarNode varNode) {
309        weight += VAR_WEIGHT;
310        return varNode;
311    }
312
313    @Override
314    public Node leaveWhileNode(final WhileNode whileNode) {
315        weight += LOOP_WEIGHT;
316        return whileNode;
317    }
318
319    @Override
320    public Node leaveWithNode(final WithNode withNode) {
321        weight += WITH_WEIGHT;
322        return withNode;
323    }
324
325    @Override
326    public Node leaveADD(final UnaryNode unaryNode) {
327        return unaryNodeWeight(unaryNode);
328    }
329
330    @Override
331    public Node leaveBIT_NOT(final UnaryNode unaryNode) {
332        return unaryNodeWeight(unaryNode);
333    }
334
335    @Override
336    public Node leaveDECINC(final UnaryNode unaryNode) {
337         return unaryNodeWeight(unaryNode);
338    }
339
340    @Override
341    public Node leaveDELETE(final UnaryNode unaryNode) {
342        return runtimeNodeWeight(unaryNode);
343    }
344
345    @Override
346    public Node leaveNEW(final UnaryNode unaryNode) {
347        weight += NEW_WEIGHT;
348        return unaryNode;
349    }
350
351    @Override
352    public Node leaveNOT(final UnaryNode unaryNode) {
353        return unaryNodeWeight(unaryNode);
354    }
355
356    @Override
357    public Node leaveSUB(final UnaryNode unaryNode) {
358        return unaryNodeWeight(unaryNode);
359    }
360
361    @Override
362    public Node leaveTYPEOF(final UnaryNode unaryNode) {
363        return runtimeNodeWeight(unaryNode);
364    }
365
366    @Override
367    public Node leaveVOID(final UnaryNode unaryNode) {
368        return unaryNodeWeight(unaryNode);
369    }
370
371    @Override
372    public Node leaveADD(final BinaryNode binaryNode) {
373        weight += ADD_WEIGHT;
374        return binaryNode;
375    }
376
377    @Override
378    public Node leaveAND(final BinaryNode binaryNode) {
379        return binaryNodeWeight(binaryNode);
380    }
381
382    @Override
383    public Node leaveASSIGN(final BinaryNode binaryNode) {
384        return binaryNodeWeight(binaryNode);
385    }
386
387    @Override
388    public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
389        weight += ADD_WEIGHT;
390        return binaryNode;
391    }
392
393    @Override
394    public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) {
395        return binaryNodeWeight(binaryNode);
396    }
397
398    @Override
399    public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) {
400        return binaryNodeWeight(binaryNode);
401    }
402
403    @Override
404    public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) {
405        return binaryNodeWeight(binaryNode);
406    }
407
408    @Override
409    public Node leaveASSIGN_DIV(final BinaryNode binaryNode) {
410        return binaryNodeWeight(binaryNode);
411    }
412
413    @Override
414    public Node leaveASSIGN_MOD(final BinaryNode binaryNode) {
415        return binaryNodeWeight(binaryNode);
416    }
417
418    @Override
419    public Node leaveASSIGN_MUL(final BinaryNode binaryNode) {
420        return binaryNodeWeight(binaryNode);
421    }
422
423    @Override
424    public Node leaveASSIGN_SAR(final BinaryNode binaryNode) {
425        return binaryNodeWeight(binaryNode);
426    }
427
428    @Override
429    public Node leaveASSIGN_SHL(final BinaryNode binaryNode) {
430        return binaryNodeWeight(binaryNode);
431    }
432
433    @Override
434    public Node leaveASSIGN_SHR(final BinaryNode binaryNode) {
435        return binaryNodeWeight(binaryNode);
436    }
437
438    @Override
439    public Node leaveASSIGN_SUB(final BinaryNode binaryNode) {
440        return binaryNodeWeight(binaryNode);
441    }
442
443    @Override
444    public Node leaveARROW(final BinaryNode binaryNode) {
445        return binaryNodeWeight(binaryNode);
446    }
447
448    @Override
449    public Node leaveBIT_AND(final BinaryNode binaryNode) {
450        return binaryNodeWeight(binaryNode);
451    }
452
453    @Override
454    public Node leaveBIT_OR(final BinaryNode binaryNode) {
455        return binaryNodeWeight(binaryNode);
456    }
457
458    @Override
459    public Node leaveBIT_XOR(final BinaryNode binaryNode) {
460        return binaryNodeWeight(binaryNode);
461    }
462
463    @Override
464    public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
465        return binaryNodeWeight(binaryNode);
466    }
467
468    @Override
469    public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
470        return binaryNodeWeight(binaryNode);
471    }
472
473    @Override
474    public Node leaveDIV(final BinaryNode binaryNode) {
475        return binaryNodeWeight(binaryNode);
476    }
477
478    @Override
479    public Node leaveEQ(final BinaryNode binaryNode) {
480        return compareWeight(binaryNode);
481    }
482
483    @Override
484    public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
485        return compareWeight(binaryNode);
486    }
487
488    @Override
489    public Node leaveGE(final BinaryNode binaryNode) {
490        return compareWeight(binaryNode);
491    }
492
493    @Override
494    public Node leaveGT(final BinaryNode binaryNode) {
495        return compareWeight(binaryNode);
496    }
497
498    @Override
499    public Node leaveIN(final BinaryNode binaryNode) {
500        weight += CALL_WEIGHT;
501        return binaryNode;
502    }
503
504    @Override
505    public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
506        weight += CALL_WEIGHT;
507        return binaryNode;
508    }
509
510    @Override
511    public Node leaveLE(final BinaryNode binaryNode) {
512        return compareWeight(binaryNode);
513    }
514
515    @Override
516    public Node leaveLT(final BinaryNode binaryNode) {
517        return compareWeight(binaryNode);
518    }
519
520    @Override
521    public Node leaveMOD(final BinaryNode binaryNode) {
522        return binaryNodeWeight(binaryNode);
523    }
524
525    @Override
526    public Node leaveMUL(final BinaryNode binaryNode) {
527        return binaryNodeWeight(binaryNode);
528    }
529
530    @Override
531    public Node leaveNE(final BinaryNode binaryNode) {
532        return compareWeight(binaryNode);
533    }
534
535    @Override
536    public Node leaveNE_STRICT(final BinaryNode binaryNode) {
537        return compareWeight(binaryNode);
538    }
539
540    @Override
541    public Node leaveOR(final BinaryNode binaryNode) {
542        return binaryNodeWeight(binaryNode);
543    }
544
545    @Override
546    public Node leaveSAR(final BinaryNode binaryNode) {
547        return binaryNodeWeight(binaryNode);
548    }
549
550    @Override
551    public Node leaveSHL(final BinaryNode binaryNode) {
552        return binaryNodeWeight(binaryNode);
553    }
554
555    @Override
556    public Node leaveSHR(final BinaryNode binaryNode) {
557        return binaryNodeWeight(binaryNode);
558    }
559
560    @Override
561    public Node leaveSUB(final BinaryNode binaryNode) {
562        return binaryNodeWeight(binaryNode);
563    }
564
565    private Node unaryNodeWeight(final UnaryNode unaryNode) {
566        weight += 1;
567        return unaryNode;
568    }
569
570    private Node binaryNodeWeight(final BinaryNode binaryNode) {
571        weight += 1;
572        return binaryNode;
573    }
574
575    private Node runtimeNodeWeight(final UnaryNode unaryNode) {
576        weight += CALL_WEIGHT;
577        return unaryNode;
578    }
579
580    private Node compareWeight(final BinaryNode binaryNode) {
581        weight += COMPARE_WEIGHT;
582        return binaryNode;
583    }
584}
585