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