Compiler.java revision 1017:1f2fa7bd6d95
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 static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 29import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 30import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 31import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 32import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 33import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 34import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote; 35 36import java.io.File; 37import java.lang.invoke.MethodType; 38import java.util.Arrays; 39import java.util.Collections; 40import java.util.Comparator; 41import java.util.HashMap; 42import java.util.Iterator; 43import java.util.LinkedHashMap; 44import java.util.LinkedList; 45import java.util.List; 46import java.util.Map; 47import java.util.Set; 48import java.util.TreeMap; 49import java.util.concurrent.atomic.AtomicInteger; 50import java.util.function.Consumer; 51import java.util.logging.Level; 52import jdk.internal.dynalink.support.NameCodec; 53import jdk.nashorn.internal.codegen.types.Type; 54import jdk.nashorn.internal.ir.Expression; 55import jdk.nashorn.internal.ir.FunctionNode; 56import jdk.nashorn.internal.ir.Optimistic; 57import jdk.nashorn.internal.ir.debug.ClassHistogramElement; 58import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; 59import jdk.nashorn.internal.runtime.CodeInstaller; 60import jdk.nashorn.internal.runtime.Context; 61import jdk.nashorn.internal.runtime.ErrorManager; 62import jdk.nashorn.internal.runtime.FunctionInitializer; 63import jdk.nashorn.internal.runtime.ParserException; 64import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 65import jdk.nashorn.internal.runtime.ScriptEnvironment; 66import jdk.nashorn.internal.runtime.ScriptObject; 67import jdk.nashorn.internal.runtime.ScriptRuntime; 68import jdk.nashorn.internal.runtime.Source; 69import jdk.nashorn.internal.runtime.logging.DebugLogger; 70import jdk.nashorn.internal.runtime.logging.Loggable; 71import jdk.nashorn.internal.runtime.logging.Logger; 72 73/** 74 * Responsible for converting JavaScripts to java byte code. Main entry 75 * point for code generator. The compiler may also install classes given some 76 * predefined Code installation policy, given to it at construction time. 77 * @see CodeInstaller 78 */ 79@Logger(name="compiler") 80public final class Compiler implements Loggable { 81 82 /** Name of the scripts package */ 83 public static final String SCRIPTS_PACKAGE = "jdk/nashorn/internal/scripts"; 84 85 /** Name of the objects package */ 86 public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; 87 88 private final ScriptEnvironment env; 89 90 private final Source source; 91 92 private final String sourceName; 93 94 private final ErrorManager errors; 95 96 private final boolean optimistic; 97 98 private final Map<String, byte[]> bytecode; 99 100 private final Set<CompileUnit> compileUnits; 101 102 private final ConstantData constantData; 103 104 private final CodeInstaller<ScriptEnvironment> installer; 105 106 /** logger for compiler, trampolines, splits and related code generation events 107 * that affect classes */ 108 private final DebugLogger log; 109 110 private final Context context; 111 112 private final TypeMap types; 113 114 // Runtime scope in effect at the time of the compilation. Used to evaluate types of expressions and prevent overly 115 // optimistic assumptions (which will lead to unnecessary deoptimizing recompilations). 116 private final TypeEvaluator typeEvaluator; 117 118 private final boolean strict; 119 120 private final boolean onDemand; 121 122 /** 123 * If this is a recompilation, this is how we pass in the invalidations, e.g. programPoint=17, Type == int means 124 * that using whatever was at program point 17 as an int failed. 125 */ 126 private final Map<Integer, Type> invalidatedProgramPoints; 127 128 /** 129 * Descriptor of the location where we write the type information after compilation. 130 */ 131 private final Object typeInformationFile; 132 133 /** 134 * Compile unit name of first compile unit - this prefix will be used for all 135 * classes that a compilation generates. 136 */ 137 private final String firstCompileUnitName; 138 139 /** 140 * Contains the program point that should be used as the continuation entry point, as well as all previous 141 * continuation entry points executed as part of a single logical invocation of the function. In practical terms, if 142 * we execute a rest-of method from the program point 17, but then we hit deoptimization again during it at program 143 * point 42, and execute a rest-of method from the program point 42, and then we hit deoptimization again at program 144 * point 57 and are compiling a rest-of method for it, the values in the array will be [57, 42, 17]. This is only 145 * set when compiling a rest-of method. If this method is a rest-of for a non-rest-of method, the array will have 146 * one element. If it is a rest-of for a rest-of, the array will have two elements, and so on. 147 */ 148 private final int[] continuationEntryPoints; 149 150 /** 151 * ScriptFunction data for what is being compile, where applicable. 152 * TODO: make this immutable, propagate it through the CompilationPhases 153 */ 154 private RecompilableScriptFunctionData compiledFunction; 155 156 /** 157 * Compilation phases that a compilation goes through 158 */ 159 public static class CompilationPhases implements Iterable<CompilationPhase> { 160 161 /** Singleton that describes a standard eager compilation - this includes code installation */ 162 public final static CompilationPhases COMPILE_ALL = new CompilationPhases( 163 "Compile all", 164 new CompilationPhase[] { 165 CompilationPhase.CONSTANT_FOLDING_PHASE, 166 CompilationPhase.LOWERING_PHASE, 167 CompilationPhase.PROGRAM_POINT_PHASE, 168 CompilationPhase.TRANSFORM_BUILTINS_PHASE, 169 CompilationPhase.SPLITTING_PHASE, 170 CompilationPhase.SYMBOL_ASSIGNMENT_PHASE, 171 CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE, 172 CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE, 173 CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, 174 CompilationPhase.BYTECODE_GENERATION_PHASE, 175 CompilationPhase.INSTALL_PHASE 176 }); 177 178 /** Compile all for a rest of method */ 179 public final static CompilationPhases COMPILE_ALL_RESTOF = 180 COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE); 181 182 /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */ 183 public final static CompilationPhases COMPILE_ALL_NO_INSTALL = 184 COMPILE_ALL. 185 removeLast(). 186 setDescription("Compile without install"); 187 188 /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */ 189 public final static CompilationPhases COMPILE_UPTO_BYTECODE = 190 COMPILE_ALL. 191 removeLast(). 192 removeLast(). 193 setDescription("Compile upto bytecode"); 194 195 /** 196 * Singleton that describes back end of method generation, given that we have generated the normal 197 * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE} 198 */ 199 public final static CompilationPhases COMPILE_FROM_BYTECODE = new CompilationPhases( 200 "Generate bytecode and install", 201 new CompilationPhase[] { 202 CompilationPhase.BYTECODE_GENERATION_PHASE, 203 CompilationPhase.INSTALL_PHASE 204 }); 205 206 /** 207 * Singleton that describes restOf method generation, given that we have generated the normal 208 * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE} 209 */ 210 public final static CompilationPhases COMPILE_FROM_BYTECODE_RESTOF = 211 COMPILE_FROM_BYTECODE. 212 addFirst(CompilationPhase.REUSE_COMPILE_UNITS_PHASE). 213 setDescription("Generate bytecode and install - RestOf method"); 214 215 private final List<CompilationPhase> phases; 216 217 private final String desc; 218 219 private CompilationPhases(final String desc, final CompilationPhase... phases) { 220 this.desc = desc; 221 222 final List<CompilationPhase> newPhases = new LinkedList<>(); 223 newPhases.addAll(Arrays.asList(phases)); 224 this.phases = Collections.unmodifiableList(newPhases); 225 } 226 227 @Override 228 public String toString() { 229 return "'" + desc + "' " + phases.toString(); 230 } 231 232 private CompilationPhases setDescription(final String desc) { 233 return new CompilationPhases(desc, phases.toArray(new CompilationPhase[phases.size()])); 234 } 235 236 private CompilationPhases removeLast() { 237 final LinkedList<CompilationPhase> list = new LinkedList<>(phases); 238 list.removeLast(); 239 return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 240 } 241 242 private CompilationPhases addFirst(final CompilationPhase phase) { 243 if (phases.contains(phase)) { 244 return this; 245 } 246 final LinkedList<CompilationPhase> list = new LinkedList<>(phases); 247 list.addFirst(phase); 248 return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 249 } 250 251 @SuppressWarnings("unused") //TODO I'll use this soon 252 private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) { 253 final LinkedList<CompilationPhase> list = new LinkedList<>(); 254 for (final CompilationPhase p : phases) { 255 list.add(p == phase ? newPhase : p); 256 } 257 return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 258 } 259 260 private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) { 261 final LinkedList<CompilationPhase> list = new LinkedList<>(); 262 for (final CompilationPhase p : phases) { 263 list.add(p); 264 if (p == phase) { 265 list.add(newPhase); 266 } 267 } 268 return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 269 } 270 271 boolean contains(final CompilationPhase phase) { 272 return phases.contains(phase); 273 } 274 275 @Override 276 public Iterator<CompilationPhase> iterator() { 277 return phases.iterator(); 278 } 279 280 boolean isRestOfCompilation() { 281 return this == COMPILE_ALL_RESTOF || this == COMPILE_FROM_BYTECODE_RESTOF; 282 } 283 284 String getDesc() { 285 return desc; 286 } 287 288 String toString(final String prefix) { 289 final StringBuilder sb = new StringBuilder(); 290 for (final CompilationPhase phase : phases) { 291 sb.append(prefix).append(phase).append('\n'); 292 } 293 return sb.toString(); 294 } 295 } 296 297 /** 298 * This array contains names that need to be reserved at the start 299 * of a compile, to avoid conflict with variable names later introduced. 300 * See {@link CompilerConstants} for special names used for structures 301 * during a compile. 302 */ 303 private static String[] RESERVED_NAMES = { 304 SCOPE.symbolName(), 305 THIS.symbolName(), 306 RETURN.symbolName(), 307 CALLEE.symbolName(), 308 VARARGS.symbolName(), 309 ARGUMENTS.symbolName() 310 }; 311 312 // per instance 313 private final int compilationId = COMPILATION_ID.getAndIncrement(); 314 315 // per instance 316 private final AtomicInteger nextCompileUnitId = new AtomicInteger(0); 317 318 private static final AtomicInteger COMPILATION_ID = new AtomicInteger(0); 319 320 /** 321 * Constructor 322 * 323 * @param context context 324 * @param env script environment 325 * @param installer code installer 326 * @param source source to compile 327 * @param errors error manager 328 * @param isStrict is this a strict compilation 329 */ 330 public Compiler( 331 final Context context, 332 final ScriptEnvironment env, 333 final CodeInstaller<ScriptEnvironment> installer, 334 final Source source, 335 final ErrorManager errors, 336 final boolean isStrict) { 337 this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null); 338 } 339 340 /** 341 * Constructor 342 * 343 * @param context context 344 * @param env script environment 345 * @param installer code installer 346 * @param source source to compile 347 * @param errors error manager 348 * @param isStrict is this a strict compilation 349 * @param isOnDemand is this an on demand compilation 350 * @param compiledFunction compiled function, if any 351 * @param types parameter and return value type information, if any is known 352 * @param invalidatedProgramPoints invalidated program points for recompilation 353 * @param typeInformationFile descriptor of the location where type information is persisted 354 * @param continuationEntryPoints continuation entry points for restof method 355 * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} 356 */ 357 public Compiler( 358 final Context context, 359 final ScriptEnvironment env, 360 final CodeInstaller<ScriptEnvironment> installer, 361 final Source source, 362 final ErrorManager errors, 363 final boolean isStrict, 364 final boolean isOnDemand, 365 final RecompilableScriptFunctionData compiledFunction, 366 final TypeMap types, 367 final Map<Integer, Type> invalidatedProgramPoints, 368 final Object typeInformationFile, 369 final int[] continuationEntryPoints, 370 final ScriptObject runtimeScope) { 371 this.context = context; 372 this.env = env; 373 this.installer = installer; 374 this.constantData = new ConstantData(); 375 this.compileUnits = CompileUnit.createCompileUnitSet(); 376 this.bytecode = new LinkedHashMap<>(); 377 this.log = initLogger(context); 378 this.source = source; 379 this.errors = errors; 380 this.sourceName = FunctionNode.getSourceName(source); 381 this.onDemand = isOnDemand; 382 this.compiledFunction = compiledFunction; 383 this.types = types; 384 this.invalidatedProgramPoints = invalidatedProgramPoints == null ? new HashMap<Integer, Type>() : invalidatedProgramPoints; 385 this.typeInformationFile = typeInformationFile; 386 this.continuationEntryPoints = continuationEntryPoints == null ? null: continuationEntryPoints.clone(); 387 this.typeEvaluator = new TypeEvaluator(this, runtimeScope); 388 this.firstCompileUnitName = firstCompileUnitName(); 389 this.strict = isStrict; 390 391 this.optimistic = env._optimistic_types; 392 } 393 394 private static String safeSourceName(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final Source source) { 395 String baseName = new File(source.getName()).getName(); 396 397 final int index = baseName.lastIndexOf(".js"); 398 if (index != -1) { 399 baseName = baseName.substring(0, index); 400 } 401 402 baseName = baseName.replace('.', '_').replace('-', '_'); 403 if (!env._loader_per_compile) { 404 baseName = baseName + installer.getUniqueScriptId(); 405 } 406 407 final String mangled = NameCodec.encode(baseName); 408 return mangled != null ? mangled : baseName; 409 } 410 411 private String firstCompileUnitName() { 412 final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE). 413 append('/'). 414 append(CompilerConstants.DEFAULT_SCRIPT_NAME.symbolName()). 415 append('$'); 416 417 if (isOnDemandCompilation()) { 418 sb.append(RecompilableScriptFunctionData.RECOMPILATION_PREFIX); 419 } 420 421 if (compilationId > 0) { 422 sb.append(compilationId).append('$'); 423 } 424 425 if (types != null && compiledFunction.getFunctionNodeId() > 0) { 426 sb.append(compiledFunction.getFunctionNodeId()); 427 final Type[] paramTypes = types.getParameterTypes(compiledFunction.getFunctionNodeId()); 428 for (final Type t : paramTypes) { 429 sb.append(Type.getShortSignatureDescriptor(t)); 430 } 431 sb.append('$'); 432 } 433 434 sb.append(Compiler.safeSourceName(env, installer, source)); 435 436 return sb.toString(); 437 } 438 439 void declareLocalSymbol(final String symbolName) { 440 typeEvaluator.declareLocalSymbol(symbolName); 441 } 442 443 void setData(final RecompilableScriptFunctionData data) { 444 assert this.compiledFunction == null : data; 445 this.compiledFunction = data; 446 } 447 448 @Override 449 public DebugLogger getLogger() { 450 return log; 451 } 452 453 @Override 454 public DebugLogger initLogger(final Context ctxt) { 455 return ctxt.getLogger(this.getClass(), new Consumer<DebugLogger>() { 456 @Override 457 public void accept(final DebugLogger newLogger) { 458 if (!Compiler.this.getScriptEnvironment()._lazy_compilation) { 459 newLogger.warning("WARNING: Running with lazy compilation switched off. This is not a default setting."); 460 } 461 } 462 }); 463 } 464 465 ScriptEnvironment getScriptEnvironment() { 466 return env; 467 } 468 469 boolean isOnDemandCompilation() { 470 return onDemand; 471 } 472 473 boolean useOptimisticTypes() { 474 return optimistic; 475 } 476 477 Context getContext() { 478 return context; 479 } 480 481 Type getOptimisticType(final Optimistic node) { 482 return typeEvaluator.getOptimisticType(node); 483 } 484 485 /** 486 * Returns true if the expression can be safely evaluated, and its value is an object known to always use 487 * String as the type of its property names retrieved through 488 * {@link ScriptRuntime#toPropertyIterator(Object)}. It is used to avoid optimistic assumptions about its 489 * property name types. 490 * @param expr the expression to test 491 * @return true if the expression can be safely evaluated, and its value is an object known to always use 492 * String as the type of its property iterators. 493 */ 494 boolean hasStringPropertyIterator(final Expression expr) { 495 return typeEvaluator.hasStringPropertyIterator(expr); 496 } 497 498 void addInvalidatedProgramPoint(final int programPoint, final Type type) { 499 invalidatedProgramPoints.put(programPoint, type); 500 } 501 502 503 /** 504 * Returns a copy of this compiler's current mapping of invalidated optimistic program points to their types. The 505 * copy is not live with regard to changes in state in this compiler instance, and is mutable. 506 * @return a copy of this compiler's current mapping of invalidated optimistic program points to their types. 507 */ 508 public Map<Integer, Type> getInvalidatedProgramPoints() { 509 return invalidatedProgramPoints == null ? null : new TreeMap<>(invalidatedProgramPoints); 510 } 511 512 TypeMap getTypeMap() { 513 return types; 514 } 515 516 MethodType getCallSiteType(final FunctionNode fn) { 517 if (types == null || !isOnDemandCompilation()) { 518 return null; 519 } 520 return types.getCallSiteType(fn); 521 } 522 523 Type getParamType(final FunctionNode fn, final int pos) { 524 return types == null ? null : types.get(fn, pos); 525 } 526 527 /** 528 * Do a compilation job 529 * 530 * @param functionNode function node to compile 531 * @param phases phases of compilation transforms to apply to function 532 533 * @return transformed function 534 * 535 * @throws CompilationException if error occurs during compilation 536 */ 537 public FunctionNode compile(final FunctionNode functionNode, final CompilationPhases phases) throws CompilationException { 538 539 log.finest("Starting compile job for ", DebugLogger.quote(functionNode.getName()), " phases=", quote(phases.getDesc())); 540 log.indent(); 541 542 final String name = DebugLogger.quote(functionNode.getName()); 543 544 FunctionNode newFunctionNode = functionNode; 545 546 for (final String reservedName : RESERVED_NAMES) { 547 newFunctionNode.uniqueName(reservedName); 548 } 549 550 final boolean info = log.levelFinerThanOrEqual(Level.INFO); 551 552 final DebugLogger timeLogger = env.isTimingEnabled() ? env._timing.getLogger() : null; 553 554 long time = 0L; 555 556 for (final CompilationPhase phase : phases) { 557 log.fine(phase, " starting for ", quote(name)); 558 559 try { 560 newFunctionNode = phase.apply(this, phases, newFunctionNode); 561 } catch (final ParserException error) { 562 errors.error(error); 563 if (env._dump_on_error) { 564 error.printStackTrace(env.getErr()); 565 } 566 return null; 567 } 568 569 log.fine(phase, " done for function ", quote(name)); 570 571 if (env._print_mem_usage) { 572 printMemoryUsage(functionNode, phase.toString()); 573 } 574 575 time += (env.isTimingEnabled() ? phase.getEndTime() - phase.getStartTime() : 0L); 576 } 577 578 if (typeInformationFile != null && !phases.isRestOfCompilation()) { 579 OptimisticTypesPersistence.store(typeInformationFile, invalidatedProgramPoints); 580 } 581 582 log.unindent(); 583 584 if (info) { 585 final StringBuilder sb = new StringBuilder(); 586 sb.append("Compile job for ").append(newFunctionNode.getSource()).append(':').append(quote(newFunctionNode.getName())).append(" finished"); 587 if (time > 0L && timeLogger != null) { 588 assert env.isTimingEnabled(); 589 sb.append(" in ").append(time).append(" ms"); 590 } 591 log.info(sb); 592 } 593 594 return newFunctionNode; 595 } 596 597 Source getSource() { 598 return source; 599 } 600 601 Map<String, byte[]> getBytecode() { 602 return Collections.unmodifiableMap(bytecode); 603 } 604 605 /** 606 * Reset bytecode cache for compiler reuse. 607 */ 608 void clearBytecode() { 609 bytecode.clear(); 610 } 611 612 CompileUnit getFirstCompileUnit() { 613 assert !compileUnits.isEmpty(); 614 return compileUnits.iterator().next(); 615 } 616 617 Set<CompileUnit> getCompileUnits() { 618 return compileUnits; 619 } 620 621 ConstantData getConstantData() { 622 return constantData; 623 } 624 625 CodeInstaller<ScriptEnvironment> getCodeInstaller() { 626 return installer; 627 } 628 629 void addClass(final String name, final byte[] code) { 630 bytecode.put(name, code); 631 } 632 633 String nextCompileUnitName() { 634 final StringBuilder sb = new StringBuilder(firstCompileUnitName); 635 final int cuid = nextCompileUnitId.getAndIncrement(); 636 if (cuid > 0) { 637 sb.append("$cu").append(cuid); 638 } 639 640 return sb.toString(); 641 } 642 643 Map<Integer, FunctionInitializer> functionInitializers; 644 645 void addFunctionInitializer(final RecompilableScriptFunctionData functionData, final FunctionNode functionNode) { 646 if (functionInitializers == null) { 647 functionInitializers = new HashMap<>(); 648 } 649 if (!functionInitializers.containsKey(functionData)) { 650 functionInitializers.put(functionData.getFunctionNodeId(), new FunctionInitializer(functionNode)); 651 } 652 } 653 654 Map<Integer, FunctionInitializer> getFunctionInitializers() { 655 return functionInitializers; 656 } 657 658 /** 659 * Persist current compilation with the given {@code cacheKey}. 660 * @param cacheKey cache key 661 * @param functionNode function node 662 */ 663 public void persistClassInfo(final String cacheKey, final FunctionNode functionNode) { 664 if (cacheKey != null && env._persistent_cache) { 665 Map<Integer, FunctionInitializer> initializers; 666 // If this is an on-demand compilation create a function initializer for the function being compiled. 667 // Otherwise use function initializer map generated by codegen. 668 if (functionInitializers == null) { 669 initializers = new HashMap<>(); 670 final FunctionInitializer initializer = new FunctionInitializer(functionNode, getInvalidatedProgramPoints()); 671 initializers.put(functionNode.getId(), initializer); 672 } else { 673 initializers = functionInitializers; 674 } 675 final String mainClassName = getFirstCompileUnit().getUnitClassName(); 676 installer.storeScript(cacheKey, source, mainClassName, bytecode, initializers, constantData.toArray(), compilationId); 677 } 678 } 679 680 /** 681 * Make sure the next compilation id is greater than {@code value}. 682 * @param value compilation id value 683 */ 684 public static void updateCompilationId(final int value) { 685 if (value >= COMPILATION_ID.get()) { 686 COMPILATION_ID.set(value + 1); 687 } 688 } 689 690 CompileUnit addCompileUnit(final long initialWeight) { 691 final CompileUnit compileUnit = createCompileUnit(initialWeight); 692 compileUnits.add(compileUnit); 693 log.fine("Added compile unit ", compileUnit); 694 return compileUnit; 695 } 696 697 CompileUnit createCompileUnit(final String unitClassName, final long initialWeight) { 698 final ClassEmitter classEmitter = new ClassEmitter(context, sourceName, unitClassName, isStrict()); 699 final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); 700 classEmitter.begin(); 701 702 return compileUnit; 703 } 704 705 private CompileUnit createCompileUnit(final long initialWeight) { 706 return createCompileUnit(nextCompileUnitName(), initialWeight); 707 } 708 709 boolean isStrict() { 710 return strict; 711 } 712 713 void replaceCompileUnits(final Set<CompileUnit> newUnits) { 714 compileUnits.clear(); 715 compileUnits.addAll(newUnits); 716 } 717 718 CompileUnit findUnit(final long weight) { 719 for (final CompileUnit unit : compileUnits) { 720 if (unit.canHold(weight)) { 721 unit.addWeight(weight); 722 return unit; 723 } 724 } 725 726 return addCompileUnit(weight); 727 } 728 729 /** 730 * Convert a package/class name to a binary name. 731 * 732 * @param name Package/class name. 733 * @return Binary name. 734 */ 735 public static String binaryName(final String name) { 736 return name.replace('/', '.'); 737 } 738 739 RecompilableScriptFunctionData getScriptFunctionData(final int functionId) { 740 return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId); 741 } 742 743 boolean isGlobalSymbol(final FunctionNode fn, final String name) { 744 return getScriptFunctionData(fn.getId()).isGlobalSymbol(fn, name); 745 } 746 747 int[] getContinuationEntryPoints() { 748 return continuationEntryPoints; 749 } 750 751 Type getInvalidatedProgramPointType(final int programPoint) { 752 return invalidatedProgramPoints.get(programPoint); 753 } 754 755 private void printMemoryUsage(final FunctionNode functionNode, final String phaseName) { 756 if (!log.isEnabled()) { 757 return; 758 } 759 760 log.info(phaseName, "finished. Doing IR size calculation..."); 761 762 final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification()); 763 osc.calculateObjectSize(functionNode); 764 765 final List<ClassHistogramElement> list = osc.getClassHistogram(); 766 final StringBuilder sb = new StringBuilder(); 767 final long totalSize = osc.calculateObjectSize(functionNode); 768 769 sb.append(phaseName). 770 append(" Total size = "). 771 append(totalSize / 1024 / 1024). 772 append("MB"); 773 log.info(sb); 774 775 Collections.sort(list, new Comparator<ClassHistogramElement>() { 776 @Override 777 public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { 778 final long diff = o1.getBytes() - o2.getBytes(); 779 if (diff < 0) { 780 return 1; 781 } else if (diff > 0) { 782 return -1; 783 } else { 784 return 0; 785 } 786 } 787 }); 788 for (final ClassHistogramElement e : list) { 789 final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances()); 790 log.info(line); 791 if (e.getBytes() < totalSize / 200) { 792 log.info(" ..."); 793 break; // never mind, so little memory anyway 794 } 795 } 796 } 797} 798