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 26 package jdk.nashorn.internal.codegen; 27 28 import java.util.List; 29 import java.util.Map; 30 import jdk.nashorn.internal.ir.AccessNode; 31 import jdk.nashorn.internal.ir.BinaryNode; 32 import jdk.nashorn.internal.ir.Block; 33 import jdk.nashorn.internal.ir.BreakNode; 34 import jdk.nashorn.internal.ir.CallNode; 35 import jdk.nashorn.internal.ir.CatchNode; 36 import jdk.nashorn.internal.ir.ContinueNode; 37 import jdk.nashorn.internal.ir.ExpressionStatement; 38 import jdk.nashorn.internal.ir.ForNode; 39 import jdk.nashorn.internal.ir.FunctionNode; 40 import jdk.nashorn.internal.ir.IdentNode; 41 import jdk.nashorn.internal.ir.IfNode; 42 import jdk.nashorn.internal.ir.IndexNode; 43 import jdk.nashorn.internal.ir.JumpToInlinedFinally; 44 import jdk.nashorn.internal.ir.LexicalContext; 45 import jdk.nashorn.internal.ir.LiteralNode; 46 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 47 import jdk.nashorn.internal.ir.Node; 48 import jdk.nashorn.internal.ir.ObjectNode; 49 import jdk.nashorn.internal.ir.PropertyNode; 50 import jdk.nashorn.internal.ir.ReturnNode; 51 import jdk.nashorn.internal.ir.RuntimeNode; 52 import jdk.nashorn.internal.ir.SplitNode; 53 import jdk.nashorn.internal.ir.Splittable; 54 import jdk.nashorn.internal.ir.SwitchNode; 55 import jdk.nashorn.internal.ir.ThrowNode; 56 import jdk.nashorn.internal.ir.TryNode; 57 import jdk.nashorn.internal.ir.UnaryNode; 58 import jdk.nashorn.internal.ir.VarNode; 59 import jdk.nashorn.internal.ir.WhileNode; 60 import jdk.nashorn.internal.ir.WithNode; 61 import 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 */ 68 final 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 + identNode.getName().length() * 2; 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 }