Compiler.java revision 1002:2f0161551858
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.EnumSet; 42import java.util.HashMap; 43import java.util.Iterator; 44import java.util.LinkedHashMap; 45import java.util.LinkedList; 46import java.util.List; 47import java.util.Map; 48import java.util.Set; 49import java.util.TreeMap; 50import java.util.concurrent.atomic.AtomicInteger; 51import java.util.function.Consumer; 52import java.util.logging.Level; 53import jdk.internal.dynalink.support.NameCodec; 54import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 55import jdk.nashorn.internal.codegen.types.Type; 56import jdk.nashorn.internal.ir.FunctionNode; 57import jdk.nashorn.internal.ir.Optimistic; 58import jdk.nashorn.internal.ir.debug.ClassHistogramElement; 59import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; 60import jdk.nashorn.internal.runtime.CodeInstaller; 61import jdk.nashorn.internal.runtime.Context; 62import jdk.nashorn.internal.runtime.ErrorManager; 63import jdk.nashorn.internal.runtime.FunctionInitializer; 64import jdk.nashorn.internal.runtime.ParserException; 65import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 66import jdk.nashorn.internal.runtime.ScriptEnvironment; 67import jdk.nashorn.internal.runtime.ScriptObject; 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 private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) { 252 final LinkedList<CompilationPhase> list = new LinkedList<>(); 253 for (final CompilationPhase p : phases) { 254 list.add(p); 255 if (p == phase) { 256 list.add(newPhase); 257 } 258 } 259 return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 260 } 261 262 boolean contains(final CompilationPhase phase) { 263 return phases.contains(phase); 264 } 265 266 @Override 267 public Iterator<CompilationPhase> iterator() { 268 return phases.iterator(); 269 } 270 271 boolean isRestOfCompilation() { 272 return this == COMPILE_ALL_RESTOF || this == COMPILE_FROM_BYTECODE_RESTOF; 273 } 274 275 String getDesc() { 276 return desc; 277 } 278 279 String toString(final String prefix) { 280 final StringBuilder sb = new StringBuilder(); 281 for (final CompilationPhase phase : phases) { 282 sb.append(prefix).append(phase).append('\n'); 283 } 284 return sb.toString(); 285 } 286 } 287 288 /** 289 * This array contains names that need to be reserved at the start 290 * of a compile, to avoid conflict with variable names later introduced. 291 * See {@link CompilerConstants} for special names used for structures 292 * during a compile. 293 */ 294 private static String[] RESERVED_NAMES = { 295 SCOPE.symbolName(), 296 THIS.symbolName(), 297 RETURN.symbolName(), 298 CALLEE.symbolName(), 299 VARARGS.symbolName(), 300 ARGUMENTS.symbolName() 301 }; 302 303 // per instance 304 private final int compilationId = COMPILATION_ID.getAndIncrement(); 305 306 // per instance 307 private final AtomicInteger nextCompileUnitId = new AtomicInteger(0); 308 309 private static final AtomicInteger COMPILATION_ID = new AtomicInteger(0); 310 311 /** 312 * Constructor 313 * 314 * @param context context 315 * @param env script environment 316 * @param installer code installer 317 * @param source source to compile 318 * @param errors error manager 319 * @param isStrict is this a strict compilation 320 */ 321 public Compiler( 322 final Context context, 323 final ScriptEnvironment env, 324 final CodeInstaller<ScriptEnvironment> installer, 325 final Source source, 326 final ErrorManager errors, 327 final boolean isStrict) { 328 this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null); 329 } 330 331 /** 332 * Constructor 333 * 334 * @param context context 335 * @param env script environment 336 * @param installer code installer 337 * @param source source to compile 338 * @param errors error manager 339 * @param isStrict is this a strict compilation 340 * @param isOnDemand is this an on demand compilation 341 * @param compiledFunction compiled function, if any 342 * @param types parameter and return value type information, if any is known 343 * @param invalidatedProgramPoints invalidated program points for recompilation 344 * @param typeInformationFile descriptor of the location where type information is persisted 345 * @param continuationEntryPoints continuation entry points for restof method 346 * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} 347 */ 348 public Compiler( 349 final Context context, 350 final ScriptEnvironment env, 351 final CodeInstaller<ScriptEnvironment> installer, 352 final Source source, 353 final ErrorManager errors, 354 final boolean isStrict, 355 final boolean isOnDemand, 356 final RecompilableScriptFunctionData compiledFunction, 357 final TypeMap types, 358 final Map<Integer, Type> invalidatedProgramPoints, 359 final Object typeInformationFile, 360 final int[] continuationEntryPoints, 361 final ScriptObject runtimeScope) { 362 this.context = context; 363 this.env = env; 364 this.installer = installer; 365 this.constantData = new ConstantData(); 366 this.compileUnits = CompileUnit.createCompileUnitSet(); 367 this.bytecode = new LinkedHashMap<>(); 368 this.log = initLogger(context); 369 this.source = source; 370 this.errors = errors; 371 this.sourceName = FunctionNode.getSourceName(source); 372 this.onDemand = isOnDemand; 373 this.compiledFunction = compiledFunction; 374 this.types = types; 375 this.invalidatedProgramPoints = invalidatedProgramPoints == null ? new HashMap<Integer, Type>() : invalidatedProgramPoints; 376 this.typeInformationFile = typeInformationFile; 377 this.continuationEntryPoints = continuationEntryPoints == null ? null: continuationEntryPoints.clone(); 378 this.typeEvaluator = new TypeEvaluator(this, runtimeScope); 379 this.firstCompileUnitName = firstCompileUnitName(); 380 this.strict = isStrict; 381 382 this.optimistic = env._optimistic_types; 383 } 384 385 private static String safeSourceName(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final Source source) { 386 String baseName = new File(source.getName()).getName(); 387 388 final int index = baseName.lastIndexOf(".js"); 389 if (index != -1) { 390 baseName = baseName.substring(0, index); 391 } 392 393 baseName = baseName.replace('.', '_').replace('-', '_'); 394 if (!env._loader_per_compile) { 395 baseName = baseName + installer.getUniqueScriptId(); 396 } 397 398 final String mangled = NameCodec.encode(baseName); 399 return mangled != null ? mangled : baseName; 400 } 401 402 private String firstCompileUnitName() { 403 final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE). 404 append('/'). 405 append(CompilerConstants.DEFAULT_SCRIPT_NAME.symbolName()). 406 append('$'); 407 408 if (isOnDemandCompilation()) { 409 sb.append(RecompilableScriptFunctionData.RECOMPILATION_PREFIX); 410 } 411 412 if (compilationId > 0) { 413 sb.append(compilationId).append('$'); 414 } 415 416 if (types != null && compiledFunction.getFunctionNodeId() > 0) { 417 sb.append(compiledFunction.getFunctionNodeId()); 418 final Type[] paramTypes = types.getParameterTypes(compiledFunction.getFunctionNodeId()); 419 for (final Type t : paramTypes) { 420 sb.append(Type.getShortSignatureDescriptor(t)); 421 } 422 sb.append('$'); 423 } 424 425 sb.append(Compiler.safeSourceName(env, installer, source)); 426 427 return sb.toString(); 428 } 429 430 void declareLocalSymbol(final String symbolName) { 431 typeEvaluator.declareLocalSymbol(symbolName); 432 } 433 434 void setData(final RecompilableScriptFunctionData data) { 435 assert this.compiledFunction == null : data; 436 this.compiledFunction = data; 437 } 438 439 @Override 440 public DebugLogger getLogger() { 441 return log; 442 } 443 444 @Override 445 public DebugLogger initLogger(final Context ctxt) { 446 return ctxt.getLogger(this.getClass(), new Consumer<DebugLogger>() { 447 @Override 448 public void accept(final DebugLogger newLogger) { 449 if (!Compiler.this.getScriptEnvironment()._lazy_compilation) { 450 newLogger.warning("WARNING: Running with lazy compilation switched off. This is not a default setting."); 451 } 452 } 453 }); 454 } 455 456 ScriptEnvironment getScriptEnvironment() { 457 return env; 458 } 459 460 boolean isOnDemandCompilation() { 461 return onDemand; 462 } 463 464 boolean useOptimisticTypes() { 465 return optimistic; 466 } 467 468 Context getContext() { 469 return context; 470 } 471 472 Type getOptimisticType(final Optimistic node) { 473 return typeEvaluator.getOptimisticType(node); 474 } 475 476 void addInvalidatedProgramPoint(final int programPoint, final Type type) { 477 invalidatedProgramPoints.put(programPoint, type); 478 } 479 480 481 /** 482 * Returns a copy of this compiler's current mapping of invalidated optimistic program points to their types. The 483 * copy is not live with regard to changes in state in this compiler instance, and is mutable. 484 * @return a copy of this compiler's current mapping of invalidated optimistic program points to their types. 485 */ 486 public Map<Integer, Type> getInvalidatedProgramPoints() { 487 return invalidatedProgramPoints == null ? null : new TreeMap<>(invalidatedProgramPoints); 488 } 489 490 TypeMap getTypeMap() { 491 return types; 492 } 493 494 MethodType getCallSiteType(final FunctionNode fn) { 495 if (types == null || !isOnDemandCompilation()) { 496 return null; 497 } 498 return types.getCallSiteType(fn); 499 } 500 501 Type getParamType(final FunctionNode fn, final int pos) { 502 return types == null ? null : types.get(fn, pos); 503 } 504 505 /** 506 * Do a compilation job 507 * 508 * @param functionNode function node to compile 509 * @param phases phases of compilation transforms to apply to function 510 511 * @return transformed function 512 * 513 * @throws CompilationException if error occurs during compilation 514 */ 515 public FunctionNode compile(final FunctionNode functionNode, final CompilationPhases phases) throws CompilationException { 516 517 log.finest("Starting compile job for ", DebugLogger.quote(functionNode.getName()), " phases=", quote(phases.getDesc())); 518 log.indent(); 519 520 final String name = DebugLogger.quote(functionNode.getName()); 521 522 FunctionNode newFunctionNode = functionNode; 523 524 for (final String reservedName : RESERVED_NAMES) { 525 newFunctionNode.uniqueName(reservedName); 526 } 527 528 final boolean info = log.levelFinerThanOrEqual(Level.INFO); 529 530 final DebugLogger timeLogger = env.isTimingEnabled() ? env._timing.getLogger() : null; 531 532 long time = 0L; 533 534 for (final CompilationPhase phase : phases) { 535 log.fine(phase, " starting for ", quote(name)); 536 537 try { 538 newFunctionNode = phase.apply(this, phases, newFunctionNode); 539 } catch (final ParserException error) { 540 errors.error(error); 541 if (env._dump_on_error) { 542 error.printStackTrace(env.getErr()); 543 } 544 return null; 545 } 546 547 log.fine(phase, " done for function ", quote(name)); 548 549 if (env._print_mem_usage) { 550 printMemoryUsage(functionNode, phase.toString()); 551 } 552 553 time += (env.isTimingEnabled() ? phase.getEndTime() - phase.getStartTime() : 0L); 554 } 555 556 if (typeInformationFile != null && !phases.isRestOfCompilation()) { 557 OptimisticTypesPersistence.store(typeInformationFile, invalidatedProgramPoints); 558 } 559 560 log.unindent(); 561 562 if (info) { 563 final StringBuilder sb = new StringBuilder(); 564 sb.append("Compile job for ").append(newFunctionNode.getSource()).append(':').append(quote(newFunctionNode.getName())).append(" finished"); 565 if (time > 0L && timeLogger != null) { 566 assert env.isTimingEnabled(); 567 sb.append(" in ").append(time).append(" ms"); 568 } 569 log.info(sb); 570 } 571 572 return newFunctionNode; 573 } 574 575 Source getSource() { 576 return source; 577 } 578 579 Map<String, byte[]> getBytecode() { 580 return Collections.unmodifiableMap(bytecode); 581 } 582 583 /** 584 * Reset bytecode cache for compiler reuse. 585 */ 586 void clearBytecode() { 587 bytecode.clear(); 588 } 589 590 CompileUnit getFirstCompileUnit() { 591 assert !compileUnits.isEmpty(); 592 return compileUnits.iterator().next(); 593 } 594 595 Set<CompileUnit> getCompileUnits() { 596 return compileUnits; 597 } 598 599 ConstantData getConstantData() { 600 return constantData; 601 } 602 603 CodeInstaller<ScriptEnvironment> getCodeInstaller() { 604 return installer; 605 } 606 607 void addClass(final String name, final byte[] code) { 608 bytecode.put(name, code); 609 } 610 611 String nextCompileUnitName() { 612 final StringBuilder sb = new StringBuilder(firstCompileUnitName); 613 final int cuid = nextCompileUnitId.getAndIncrement(); 614 if (cuid > 0) { 615 sb.append("$cu").append(cuid); 616 } 617 618 return sb.toString(); 619 } 620 621 Map<Integer, FunctionInitializer> functionInitializers; 622 623 void addFunctionInitializer(final RecompilableScriptFunctionData functionData, final FunctionNode functionNode) { 624 if (functionInitializers == null) { 625 functionInitializers = new HashMap<>(); 626 } 627 if (!functionInitializers.containsKey(functionData)) { 628 functionInitializers.put(functionData.getFunctionNodeId(), new FunctionInitializer(functionNode)); 629 } 630 } 631 632 Map<Integer, FunctionInitializer> getFunctionInitializers() { 633 return functionInitializers; 634 } 635 636 /** 637 * Persist current compilation with the given {@code cacheKey}. 638 * @param cacheKey cache key 639 * @param functionNode function node 640 */ 641 public void persistClassInfo(final String cacheKey, final FunctionNode functionNode) { 642 if (cacheKey != null && env._persistent_cache) { 643 Map<Integer, FunctionInitializer> initializers; 644 // If this is an on-demand compilation create a function initializer for the function being compiled. 645 // Otherwise use function initializer map generated by codegen. 646 if (functionInitializers == null) { 647 initializers = new HashMap<>(); 648 final FunctionInitializer initializer = new FunctionInitializer(functionNode, getInvalidatedProgramPoints()); 649 initializers.put(functionNode.getId(), initializer); 650 } else { 651 initializers = functionInitializers; 652 } 653 final String mainClassName = getFirstCompileUnit().getUnitClassName(); 654 installer.storeScript(cacheKey, source, mainClassName, bytecode, initializers, constantData.toArray(), compilationId); 655 } 656 } 657 658 /** 659 * Make sure the next compilation id is greater than {@code value}. 660 * @param value compilation id value 661 */ 662 public static void updateCompilationId(final int value) { 663 if (value >= COMPILATION_ID.get()) { 664 COMPILATION_ID.set(value + 1); 665 } 666 } 667 668 CompileUnit addCompileUnit(final long initialWeight) { 669 final CompileUnit compileUnit = createCompileUnit(initialWeight); 670 compileUnits.add(compileUnit); 671 log.fine("Added compile unit ", compileUnit); 672 return compileUnit; 673 } 674 675 CompileUnit createCompileUnit(final String unitClassName, final long initialWeight) { 676 final ClassEmitter classEmitter = new ClassEmitter(context, sourceName, unitClassName, isStrict()); 677 final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); 678 679 classEmitter.begin(); 680 681 final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE)); 682 initMethod.begin(); 683 initMethod.load(Type.OBJECT, 0); 684 initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class); 685 initMethod.returnVoid(); 686 initMethod.end(); 687 688 return compileUnit; 689 } 690 691 private CompileUnit createCompileUnit(final long initialWeight) { 692 return createCompileUnit(nextCompileUnitName(), initialWeight); 693 } 694 695 boolean isStrict() { 696 return strict; 697 } 698 699 void replaceCompileUnits(final Set<CompileUnit> newUnits) { 700 compileUnits.clear(); 701 compileUnits.addAll(newUnits); 702 } 703 704 CompileUnit findUnit(final long weight) { 705 for (final CompileUnit unit : compileUnits) { 706 if (unit.canHold(weight)) { 707 unit.addWeight(weight); 708 return unit; 709 } 710 } 711 712 return addCompileUnit(weight); 713 } 714 715 /** 716 * Convert a package/class name to a binary name. 717 * 718 * @param name Package/class name. 719 * @return Binary name. 720 */ 721 public static String binaryName(final String name) { 722 return name.replace('/', '.'); 723 } 724 725 RecompilableScriptFunctionData getProgram() { 726 if (compiledFunction == null) { 727 return null; 728 } 729 return compiledFunction.getProgram(); 730 } 731 732 RecompilableScriptFunctionData getScriptFunctionData(final int functionId) { 733 return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId); 734 } 735 736 boolean isGlobalSymbol(final FunctionNode fn, final String name) { 737 return getScriptFunctionData(fn.getId()).isGlobalSymbol(fn, name); 738 } 739 740 int[] getContinuationEntryPoints() { 741 return continuationEntryPoints; 742 } 743 744 Type getInvalidatedProgramPointType(final int programPoint) { 745 return invalidatedProgramPoints.get(programPoint); 746 } 747 748 private void printMemoryUsage(final FunctionNode functionNode, final String phaseName) { 749 if (!log.isEnabled()) { 750 return; 751 } 752 753 log.info(phaseName, "finished. Doing IR size calculation..."); 754 755 final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification()); 756 osc.calculateObjectSize(functionNode); 757 758 final List<ClassHistogramElement> list = osc.getClassHistogram(); 759 final StringBuilder sb = new StringBuilder(); 760 final long totalSize = osc.calculateObjectSize(functionNode); 761 762 sb.append(phaseName). 763 append(" Total size = "). 764 append(totalSize / 1024 / 1024). 765 append("MB"); 766 log.info(sb); 767 768 Collections.sort(list, new Comparator<ClassHistogramElement>() { 769 @Override 770 public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { 771 final long diff = o1.getBytes() - o2.getBytes(); 772 if (diff < 0) { 773 return 1; 774 } else if (diff > 0) { 775 return -1; 776 } else { 777 return 0; 778 } 779 } 780 }); 781 for (final ClassHistogramElement e : list) { 782 final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances()); 783 log.info(line); 784 if (e.getBytes() < totalSize / 200) { 785 log.info(" ..."); 786 break; // never mind, so little memory anyway 787 } 788 } 789 } 790} 791