CompilationPhase.java revision 1070:34d55faf0b3a
1109412Smdodd/* 2109412Smdodd * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3109412Smdodd * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4109412Smdodd * 5109412Smdodd * This code is free software; you can redistribute it and/or modify it 6109412Smdodd * under the terms of the GNU General Public License version 2 only, as 7109412Smdodd * published by the Free Software Foundation. Oracle designates this 8109412Smdodd * particular file as subject to the "Classpath" exception as provided 9109412Smdodd * by Oracle in the LICENSE file that accompanied this code. 10109412Smdodd * 11109412Smdodd * This code is distributed in the hope that it will be useful, but WITHOUT 12109412Smdodd * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13109412Smdodd * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14109412Smdodd * version 2 for more details (a copy is included in the LICENSE file that 15109412Smdodd * accompanied this code). 16109412Smdodd * 17109412Smdodd * You should have received a copy of the GNU General Public License version 18109412Smdodd * 2 along with this work; if not, write to the Free Software Foundation, 19109412Smdodd * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20109412Smdodd * 21109412Smdodd * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22109412Smdodd * or visit www.oracle.com if you need additional information or have any 23109412Smdodd * questions. 24109412Smdodd */ 25109412Smdodd 26109412Smdoddpackage jdk.nashorn.internal.codegen; 27109412Smdodd 28109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BUILTINS_TRANSFORMED; 29109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BYTECODE_GENERATED; 30109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BYTECODE_INSTALLED; 31109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED; 32109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED; 33109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOCAL_VARIABLE_TYPES_CALCULATED; 34109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED; 35109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.OPTIMISTIC_TYPES_ASSIGNED; 36109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED; 37109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SCOPE_DEPTHS_COMPUTED; 38109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; 39109412Smdoddimport static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SYMBOLS_ASSIGNED; 40109412Smdoddimport static jdk.nashorn.internal.runtime.logging.DebugLogger.quote; 41109412Smdodd 42109412Smdoddimport java.io.PrintWriter; 43109412Smdoddimport java.util.EnumSet; 44109412Smdoddimport java.util.HashMap; 45109412Smdoddimport java.util.LinkedHashMap; 46109412Smdoddimport java.util.Map; 47109412Smdoddimport java.util.Map.Entry; 48109412Smdoddimport java.util.Set; 49109412Smdoddimport jdk.nashorn.internal.AssertsEnabled; 50109412Smdoddimport jdk.nashorn.internal.codegen.Compiler.CompilationPhases; 51109412Smdoddimport jdk.nashorn.internal.ir.FunctionNode; 52109412Smdoddimport jdk.nashorn.internal.ir.FunctionNode.CompilationState; 53109412Smdoddimport jdk.nashorn.internal.ir.LexicalContext; 54109412Smdoddimport jdk.nashorn.internal.ir.LiteralNode; 55109412Smdoddimport jdk.nashorn.internal.ir.Node; 56109412Smdoddimport jdk.nashorn.internal.ir.debug.ASTWriter; 57109412Smdoddimport jdk.nashorn.internal.ir.debug.PrintVisitor; 58109412Smdoddimport jdk.nashorn.internal.ir.visitor.NodeVisitor; 59109412Smdoddimport jdk.nashorn.internal.runtime.CodeInstaller; 60112558Smdoddimport jdk.nashorn.internal.runtime.FunctionInitializer; 61109412Smdoddimport jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 62109412Smdoddimport jdk.nashorn.internal.runtime.ScriptEnvironment; 63109412Smdoddimport jdk.nashorn.internal.runtime.logging.DebugLogger; 64109412Smdodd 65109412Smdodd/** 66109412Smdodd * A compilation phase is a step in the processes of turning a JavaScript 67109412Smdodd * FunctionNode into bytecode. It has an optional return value. 68109412Smdodd */ 69109412Smdoddenum CompilationPhase { 70109412Smdodd /** 71109412Smdodd * Constant folding pass Simple constant folding that will make elementary 72109412Smdodd * constructs go away 73109412Smdodd */ 74109412Smdodd CONSTANT_FOLDING_PHASE( 75109412Smdodd EnumSet.of( 76109412Smdodd INITIALIZED, 77109412Smdodd PARSED)) { 78109412Smdodd @Override 79109412Smdodd FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 80109412Smdodd return transformFunction(fn, new FoldConstants(compiler)); 81112558Smdodd } 82109412Smdodd 83109412Smdodd @Override 84109412Smdodd public String toString() { 85109412Smdodd return "'Constant Folding'"; 86109412Smdodd } 87109412Smdodd }, 88109412Smdodd 89109412Smdodd /** 90109412Smdodd * Lower (Control flow pass) Finalizes the control flow. Clones blocks for 91109412Smdodd * finally constructs and similar things. Establishes termination criteria 92 * for nodes Guarantee return instructions to method making sure control 93 * flow cannot fall off the end. Replacing high level nodes with lower such 94 * as runtime nodes where applicable. 95 */ 96 LOWERING_PHASE( 97 EnumSet.of( 98 INITIALIZED, 99 PARSED, 100 CONSTANT_FOLDED)) { 101 @Override 102 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 103 return transformFunction(fn, new Lower(compiler)); 104 } 105 106 @Override 107 public String toString() { 108 return "'Control Flow Lowering'"; 109 } 110 }, 111 112 /** 113 * Phase used only when doing optimistic code generation. It assigns all potentially 114 * optimistic ops a program point so that an UnwarrantedException knows from where 115 * a guess went wrong when creating the continuation to roll back this execution 116 */ 117 TRANSFORM_BUILTINS_PHASE( 118 EnumSet.of( 119 INITIALIZED, 120 PARSED, 121 CONSTANT_FOLDED, 122 LOWERED)) { 123 //we only do this if we have a param type map, otherwise this is not a specialized recompile 124 @Override 125 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 126 return setStates(transformFunction(fn, new ApplySpecialization(compiler)), BUILTINS_TRANSFORMED); 127 } 128 129 @Override 130 public String toString() { 131 return "'Builtin Replacement'"; 132 } 133 }, 134 135 /** 136 * Splitter Split the AST into several compile units based on a heuristic size calculation. 137 * Split IR can lead to scope information being changed. 138 */ 139 SPLITTING_PHASE( 140 EnumSet.of( 141 INITIALIZED, 142 PARSED, 143 CONSTANT_FOLDED, 144 LOWERED, 145 BUILTINS_TRANSFORMED)) { 146 @Override 147 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 148 final CompileUnit outermostCompileUnit = compiler.addCompileUnit(0L); 149 150 FunctionNode newFunctionNode; 151 152 //ensure elementTypes, postsets and presets exist for splitter and arraynodes 153 newFunctionNode = transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) { 154 @Override 155 public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) { 156 return literalNode.initialize(lc); 157 } 158 }); 159 160 newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true); 161 newFunctionNode = transformFunction(newFunctionNode, new SplitIntoFunctions(compiler)); 162 assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; 163 assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName()); 164 165 return newFunctionNode; 166 } 167 168 @Override 169 public String toString() { 170 return "'Code Splitting'"; 171 } 172 }, 173 174 PROGRAM_POINT_PHASE( 175 EnumSet.of( 176 INITIALIZED, 177 PARSED, 178 CONSTANT_FOLDED, 179 LOWERED, 180 BUILTINS_TRANSFORMED, 181 SPLIT)) { 182 @Override 183 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 184 return transformFunction(fn, new ProgramPoints()); 185 } 186 187 @Override 188 public String toString() { 189 return "'Program Point Calculation'"; 190 } 191 }, 192 193 SERIALIZE_SPLIT_PHASE( 194 EnumSet.of( 195 INITIALIZED, 196 PARSED, 197 CONSTANT_FOLDED, 198 LOWERED, 199 BUILTINS_TRANSFORMED, 200 SPLIT)) { 201 @Override 202 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 203 return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) { 204 @Override 205 public boolean enterFunctionNode(final FunctionNode functionNode) { 206 if (functionNode.isSplit()) { 207 compiler.serializeAst(functionNode); 208 } 209 return true; 210 } 211 }); 212 } 213 214 @Override 215 public String toString() { 216 return "'Serialize Split Functions'"; 217 } 218 }, 219 220 SYMBOL_ASSIGNMENT_PHASE( 221 EnumSet.of( 222 INITIALIZED, 223 PARSED, 224 CONSTANT_FOLDED, 225 LOWERED, 226 BUILTINS_TRANSFORMED, 227 SPLIT)) { 228 @Override 229 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 230 return transformFunction(fn, new AssignSymbols(compiler)); 231 } 232 233 @Override 234 public String toString() { 235 return "'Symbol Assignment'"; 236 } 237 }, 238 239 SCOPE_DEPTH_COMPUTATION_PHASE( 240 EnumSet.of( 241 INITIALIZED, 242 PARSED, 243 CONSTANT_FOLDED, 244 LOWERED, 245 BUILTINS_TRANSFORMED, 246 SPLIT, 247 SYMBOLS_ASSIGNED)) { 248 @Override 249 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 250 return transformFunction(fn, new FindScopeDepths(compiler)); 251 } 252 253 @Override 254 public String toString() { 255 return "'Scope Depth Computation'"; 256 } 257 }, 258 259 OPTIMISTIC_TYPE_ASSIGNMENT_PHASE( 260 EnumSet.of( 261 INITIALIZED, 262 PARSED, 263 CONSTANT_FOLDED, 264 LOWERED, 265 BUILTINS_TRANSFORMED, 266 SPLIT, 267 SYMBOLS_ASSIGNED, 268 SCOPE_DEPTHS_COMPUTED)) { 269 @Override 270 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 271 if (compiler.useOptimisticTypes()) { 272 return transformFunction(fn, new OptimisticTypesCalculator(compiler)); 273 } 274 return setStates(fn, OPTIMISTIC_TYPES_ASSIGNED); 275 } 276 277 @Override 278 public String toString() { 279 return "'Optimistic Type Assignment'"; 280 } 281 }, 282 283 LOCAL_VARIABLE_TYPE_CALCULATION_PHASE( 284 EnumSet.of( 285 INITIALIZED, 286 PARSED, 287 CONSTANT_FOLDED, 288 LOWERED, 289 BUILTINS_TRANSFORMED, 290 SPLIT, 291 SYMBOLS_ASSIGNED, 292 SCOPE_DEPTHS_COMPUTED, 293 OPTIMISTIC_TYPES_ASSIGNED)) { 294 @Override 295 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 296 final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler)); 297 final ScriptEnvironment senv = compiler.getScriptEnvironment(); 298 final PrintWriter err = senv.getErr(); 299 300 //TODO separate phase for the debug printouts for abstraction and clarity 301 if (senv._print_lower_ast || fn.getFlag(FunctionNode.IS_PRINT_LOWER_AST)) { 302 err.println("Lower AST for: " + quote(newFunctionNode.getName())); 303 err.println(new ASTWriter(newFunctionNode)); 304 } 305 306 if (senv._print_lower_parse || fn.getFlag(FunctionNode.IS_PRINT_LOWER_PARSE)) { 307 err.println("Lower AST for: " + quote(newFunctionNode.getName())); 308 err.println(new PrintVisitor(newFunctionNode)); 309 } 310 311 return newFunctionNode; 312 } 313 314 @Override 315 public String toString() { 316 return "'Local Variable Type Calculation'"; 317 } 318 }, 319 320 321 /** 322 * Reuse compile units, if they are already present. We are using the same compiler 323 * to recompile stuff 324 */ 325 REUSE_COMPILE_UNITS_PHASE( 326 EnumSet.of( 327 INITIALIZED, 328 PARSED, 329 CONSTANT_FOLDED, 330 LOWERED, 331 BUILTINS_TRANSFORMED, 332 SPLIT, 333 SYMBOLS_ASSIGNED, 334 SCOPE_DEPTHS_COMPUTED, 335 OPTIMISTIC_TYPES_ASSIGNED, 336 LOCAL_VARIABLE_TYPES_CALCULATED)) { 337 @Override 338 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 339 assert phases.isRestOfCompilation() : "reuse compile units currently only used for Rest-Of methods"; 340 341 final Map<CompileUnit, CompileUnit> map = new HashMap<>(); 342 final Set<CompileUnit> newUnits = CompileUnit.createCompileUnitSet(); 343 344 final DebugLogger log = compiler.getLogger(); 345 346 log.fine("Clearing bytecode cache"); 347 compiler.clearBytecode(); 348 349 for (final CompileUnit oldUnit : compiler.getCompileUnits()) { 350 assert map.get(oldUnit) == null; 351 final CompileUnit newUnit = createNewCompileUnit(compiler, phases); 352 log.fine("Creating new compile unit ", oldUnit, " => ", newUnit); 353 map.put(oldUnit, newUnit); 354 assert newUnit != null; 355 newUnits.add(newUnit); 356 } 357 358 log.fine("Replacing compile units in Compiler..."); 359 compiler.replaceCompileUnits(newUnits); 360 log.fine("Done"); 361 362 //replace old compile units in function nodes, if any are assigned, 363 //for example by running the splitter on this function node in a previous 364 //partial code generation 365 final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() { 366 @Override 367 CompileUnit getReplacement(CompileUnit original) { 368 return map.get(original); 369 } 370 371 @Override 372 public Node leaveDefault(final Node node) { 373 return node.ensureUniqueLabels(lc); 374 } 375 }); 376 377 return newFunctionNode; 378 } 379 380 @Override 381 public String toString() { 382 return "'Reuse Compile Units'"; 383 } 384 }, 385 386 REINITIALIZE_SERIALIZED( 387 EnumSet.of( 388 INITIALIZED, 389 PARSED, 390 CONSTANT_FOLDED, 391 LOWERED, 392 BUILTINS_TRANSFORMED, 393 SPLIT)) { 394 @Override 395 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 396 final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet(); 397 final Map<CompileUnit, CompileUnit> unitMap = new HashMap<>(); 398 399 // Ensure that the FunctionNode's compile unit is the first in the list of new units. Install phase 400 // will use that as the root class. 401 createCompileUnit(fn.getCompileUnit(), unitSet, unitMap, compiler, phases); 402 403 final FunctionNode newFn = transformFunction(fn, new ReplaceCompileUnits() { 404 @Override 405 CompileUnit getReplacement(final CompileUnit oldUnit) { 406 final CompileUnit existing = unitMap.get(oldUnit); 407 if (existing != null) { 408 return existing; 409 } 410 return createCompileUnit(oldUnit, unitSet, unitMap, compiler, phases); 411 } 412 413 @Override 414 public Node leaveFunctionNode(final FunctionNode fn2) { 415 return super.leaveFunctionNode( 416 // restore flags for deserialized nested function nodes 417 compiler.getScriptFunctionData(fn2.getId()).restoreFlags(lc, fn2)); 418 }; 419 }); 420 compiler.replaceCompileUnits(unitSet); 421 return newFn; 422 } 423 424 private CompileUnit createCompileUnit(final CompileUnit oldUnit, final Set<CompileUnit> unitSet, 425 final Map<CompileUnit, CompileUnit> unitMap, final Compiler compiler, final CompilationPhases phases) { 426 final CompileUnit newUnit = createNewCompileUnit(compiler, phases); 427 unitMap.put(oldUnit, newUnit); 428 unitSet.add(newUnit); 429 return newUnit; 430 } 431 432 @Override 433 public String toString() { 434 return "'Deserialize'"; 435 } 436 }, 437 438 /** 439 * Bytecode generation: 440 * 441 * Generate the byte code class(es) resulting from the compiled FunctionNode 442 */ 443 BYTECODE_GENERATION_PHASE( 444 EnumSet.of( 445 INITIALIZED, 446 PARSED, 447 CONSTANT_FOLDED, 448 LOWERED, 449 BUILTINS_TRANSFORMED, 450 SPLIT, 451 SYMBOLS_ASSIGNED, 452 SCOPE_DEPTHS_COMPUTED, 453 OPTIMISTIC_TYPES_ASSIGNED, 454 LOCAL_VARIABLE_TYPES_CALCULATED)) { 455 456 @Override 457 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 458 final ScriptEnvironment senv = compiler.getScriptEnvironment(); 459 460 FunctionNode newFunctionNode = fn; 461 462 //root class is special, as it is bootstrapped from createProgramFunction, thus it's skipped 463 //in CodeGeneration - the rest can be used as a working "is compile unit used" metric 464 fn.getCompileUnit().setUsed(); 465 466 compiler.getLogger().fine("Starting bytecode generation for ", quote(fn.getName()), " - restOf=", phases.isRestOfCompilation()); 467 468 final CodeGenerator codegen = new CodeGenerator(compiler, phases.isRestOfCompilation() ? compiler.getContinuationEntryPoints() : null); 469 470 try { 471 // Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program 472 // in the lazy + optimistic world. See CodeGenerator.skipFunction(). 473 newFunctionNode = transformFunction(newFunctionNode, codegen).setState(null, BYTECODE_GENERATED); 474 codegen.generateScopeCalls(); 475 } catch (final VerifyError e) { 476 if (senv._verify_code || senv._print_code) { 477 senv.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage()); 478 if (senv._dump_on_error) { 479 e.printStackTrace(senv.getErr()); 480 } 481 } else { 482 throw e; 483 } 484 } catch (final Throwable e) { 485 // Provide source file and line number being compiled when the assertion occurred 486 throw new AssertionError("Failed generating bytecode for " + fn.getSourceName() + ":" + codegen.getLastLineNumber(), e); 487 } 488 489 for (final CompileUnit compileUnit : compiler.getCompileUnits()) { 490 final ClassEmitter classEmitter = compileUnit.getClassEmitter(); 491 classEmitter.end(); 492 493 if (!compileUnit.isUsed()) { 494 compiler.getLogger().fine("Skipping unused compile unit ", compileUnit); 495 continue; 496 } 497 498 final byte[] bytecode = classEmitter.toByteArray(); 499 assert bytecode != null; 500 501 final String className = compileUnit.getUnitClassName(); 502 compiler.addClass(className, bytecode); //classes are only added to the bytecode map if compile unit is used 503 504 CompileUnit.increaseEmitCount(); 505 506 // should we verify the generated code? 507 if (senv._verify_code) { 508 compiler.getCodeInstaller().verify(bytecode); 509 } 510 511 DumpBytecode.dumpBytecode(senv, compiler.getLogger(), bytecode, className); 512 } 513 514 return newFunctionNode; 515 } 516 517 @Override 518 public String toString() { 519 return "'Bytecode Generation'"; 520 } 521 }, 522 523 INSTALL_PHASE( 524 EnumSet.of( 525 INITIALIZED, 526 PARSED, 527 CONSTANT_FOLDED, 528 LOWERED, 529 BUILTINS_TRANSFORMED, 530 SPLIT, 531 SYMBOLS_ASSIGNED, 532 SCOPE_DEPTHS_COMPUTED, 533 OPTIMISTIC_TYPES_ASSIGNED, 534 LOCAL_VARIABLE_TYPES_CALCULATED, 535 BYTECODE_GENERATED)) { 536 537 @Override 538 FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) { 539 final DebugLogger log = compiler.getLogger(); 540 541 final Map<String, Class<?>> installedClasses = new LinkedHashMap<>(); 542 543 boolean first = true; 544 Class<?> rootClass = null; 545 long length = 0L; 546 547 final CodeInstaller<ScriptEnvironment> codeInstaller = compiler.getCodeInstaller(); 548 final Map<String, byte[]> bytecode = compiler.getBytecode(); 549 550 for (final Entry<String, byte[]> entry : bytecode.entrySet()) { 551 final String className = entry.getKey(); 552 //assert !first || className.equals(compiler.getFirstCompileUnit().getUnitClassName()) : "first=" + first + " className=" + className + " != " + compiler.getFirstCompileUnit().getUnitClassName(); 553 final byte[] code = entry.getValue(); 554 length += code.length; 555 556 final Class<?> clazz = codeInstaller.install(className, code); 557 if (first) { 558 rootClass = clazz; 559 first = false; 560 } 561 installedClasses.put(className, clazz); 562 } 563 564 if (rootClass == null) { 565 throw new CompilationException("Internal compiler error: root class not found!"); 566 } 567 568 final Object[] constants = compiler.getConstantData().toArray(); 569 codeInstaller.initialize(installedClasses.values(), compiler.getSource(), constants); 570 571 // initialize transient fields on recompilable script function data 572 for (final Object constant: constants) { 573 if (constant instanceof RecompilableScriptFunctionData) { 574 ((RecompilableScriptFunctionData)constant).initTransients(compiler.getSource(), codeInstaller); 575 } 576 } 577 578 // initialize function in the compile units 579 for (final CompileUnit unit : compiler.getCompileUnits()) { 580 if (!unit.isUsed()) { 581 continue; 582 } 583 unit.setCode(installedClasses.get(unit.getUnitClassName())); 584 } 585 586 if (!compiler.isOnDemandCompilation()) { 587 // Initialize functions 588 final Map<Integer, FunctionInitializer> initializers = compiler.getFunctionInitializers(); 589 if (initializers != null) { 590 for (final Entry<Integer, FunctionInitializer> entry : initializers.entrySet()) { 591 final FunctionInitializer initializer = entry.getValue(); 592 initializer.setCode(installedClasses.get(initializer.getClassName())); 593 compiler.getScriptFunctionData(entry.getKey()).initializeCode(initializer); 594 } 595 } 596 } 597 598 if (log.isEnabled()) { 599 final StringBuilder sb = new StringBuilder(); 600 601 sb.append("Installed class '"). 602 append(rootClass.getSimpleName()). 603 append('\''). 604 append(" ["). 605 append(rootClass.getName()). 606 append(", size="). 607 append(length). 608 append(" bytes, "). 609 append(compiler.getCompileUnits().size()). 610 append(" compile unit(s)]"); 611 612 log.fine(sb.toString()); 613 } 614 615 return setStates(fn.setRootClass(null, rootClass), BYTECODE_INSTALLED); 616 } 617 618 @Override 619 public String toString() { 620 return "'Class Installation'"; 621 } 622 623 }; 624 625 /** pre conditions required for function node to which this transform is to be applied */ 626 private final EnumSet<CompilationState> pre; 627 628 /** start time of transform - used for timing, see {@link jdk.nashorn.internal.runtime.Timing} */ 629 private long startTime; 630 631 /** start time of transform - used for timing, see {@link jdk.nashorn.internal.runtime.Timing} */ 632 private long endTime; 633 634 /** boolean that is true upon transform completion */ 635 private boolean isFinished; 636 637 private CompilationPhase(final EnumSet<CompilationState> pre) { 638 this.pre = pre; 639 } 640 641 private static FunctionNode setStates(final FunctionNode functionNode, final CompilationState state) { 642 if (!AssertsEnabled.assertsEnabled()) { 643 return functionNode; 644 } 645 return transformFunction(functionNode, new NodeVisitor<LexicalContext>(new LexicalContext()) { 646 @Override 647 public Node leaveFunctionNode(final FunctionNode fn) { 648 return fn.setState(lc, state); 649 } 650 }); 651 } 652 653 /** 654 * Start a compilation phase 655 * @param compiler the compiler to use 656 * @param functionNode function to compile 657 * @return function node 658 */ 659 protected FunctionNode begin(final Compiler compiler, final FunctionNode functionNode) { 660 compiler.getLogger().indent(); 661 662 assert pre != null; 663 664 if (!functionNode.hasState(pre)) { 665 final StringBuilder sb = new StringBuilder("Compilation phase "); 666 sb.append(this). 667 append(" is not applicable to "). 668 append(quote(functionNode.getName())). 669 append("\n\tFunctionNode state = "). 670 append(functionNode.getState()). 671 append("\n\tRequired state = "). 672 append(this.pre); 673 674 throw new CompilationException(sb.toString()); 675 } 676 677 startTime = System.nanoTime(); 678 679 return functionNode; 680 } 681 682 /** 683 * End a compilation phase 684 * @param compiler the compiler 685 * @param functionNode function node to compile 686 * @return function node 687 */ 688 protected FunctionNode end(final Compiler compiler, final FunctionNode functionNode) { 689 compiler.getLogger().unindent(); 690 endTime = System.nanoTime(); 691 compiler.getScriptEnvironment()._timing.accumulateTime(toString(), endTime - startTime); 692 693 isFinished = true; 694 return functionNode; 695 } 696 697 boolean isFinished() { 698 return isFinished; 699 } 700 701 long getStartTime() { 702 return startTime; 703 } 704 705 long getEndTime() { 706 return endTime; 707 } 708 709 abstract FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode functionNode) throws CompilationException; 710 711 /** 712 * Apply a transform to a function node, returning the transfored function node. If the transform is not 713 * applicable, an exception is thrown. Every transform requires the function to have a certain number of 714 * states to operate. It can have more states set, but not fewer. The state list, i.e. the constructor 715 * arguments to any of the CompilationPhase enum entries, is a set of REQUIRED states. 716 * 717 * @param compiler compiler 718 * @param phases current complete pipeline of which this phase is one 719 * @param functionNode function node to transform 720 * 721 * @return transformed function node 722 * 723 * @throws CompilationException if function node lacks the state required to run the transform on it 724 */ 725 final FunctionNode apply(final Compiler compiler, final CompilationPhases phases, final FunctionNode functionNode) throws CompilationException { 726 assert phases.contains(this); 727 728 return end(compiler, transform(compiler, phases, begin(compiler, functionNode))); 729 } 730 731 private static FunctionNode transformFunction(final FunctionNode fn, final NodeVisitor<?> visitor) { 732 return (FunctionNode) fn.accept(visitor); 733 } 734 735 private static CompileUnit createNewCompileUnit(final Compiler compiler, final CompilationPhases phases) { 736 final StringBuilder sb = new StringBuilder(compiler.nextCompileUnitName()); 737 if (phases.isRestOfCompilation()) { 738 sb.append("$restOf"); 739 } 740 //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what 741 //fills those out anyway. Thus no need for a copy constructor 742 return compiler.createCompileUnit(sb.toString(), 0); 743 } 744} 745