src/jdk/nashorn/internal/codegen/CompilationPhase.java

Fri, 05 Jun 2015 14:46:52 +0530

author
sundar
date
Fri, 05 Jun 2015 14:46:52 +0530
changeset 1397
19263eb2ff0c
parent 1337
248dc4f11e5b
child 1490
d85f981c8cf8
child 1530
fd307cc5f58c
permissions
-rw-r--r--

8081809: Missing final modifier in method parameters (nashorn code convention)
Reviewed-by: attila, lagergren

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

mercurial