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