Compiler.java revision 971:c93b6091b11e
1218887Sdim/* 2218887Sdim * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3218887Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4218887Sdim * 5218887Sdim * This code is free software; you can redistribute it and/or modify it 6218887Sdim * under the terms of the GNU General Public License version 2 only, as 7218887Sdim * published by the Free Software Foundation. Oracle designates this 8218887Sdim * particular file as subject to the "Classpath" exception as provided 9218887Sdim * by Oracle in the LICENSE file that accompanied this code. 10218887Sdim * 11218887Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 12218887Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13218887Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14218887Sdim * version 2 for more details (a copy is included in the LICENSE file that 15218887Sdim * accompanied this code). 16243830Sdim * 17249423Sdim * You should have received a copy of the GNU General Public License version 18243830Sdim * 2 along with this work; if not, write to the Free Software Foundation, 19243830Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20218887Sdim * 21243830Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22218887Sdim * or visit www.oracle.com if you need additional information or have any 23243830Sdim * questions. 24243830Sdim */ 25243830Sdim 26234353Sdimpackage jdk.nashorn.internal.codegen; 27243830Sdim 28218887Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 29218887Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 30218887Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 31218887Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 32243830Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 33243830Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 34243830Sdimimport static jdk.nashorn.internal.runtime.logging.DebugLogger.quote; 35243830Sdim 36243830Sdimimport java.io.File; 37243830Sdimimport java.lang.invoke.MethodType; 38243830Sdimimport java.util.Arrays; 39243830Sdimimport java.util.Collections; 40243830Sdimimport java.util.Comparator; 41243830Sdimimport java.util.EnumSet; 42243830Sdimimport java.util.HashMap; 43243830Sdimimport java.util.Iterator; 44243830Sdimimport java.util.LinkedHashMap; 45243830Sdimimport java.util.LinkedList; 46243830Sdimimport java.util.List; 47243830Sdimimport java.util.Map; 48243830Sdimimport java.util.Set; 49243830Sdimimport java.util.TreeMap; 50243830Sdimimport java.util.concurrent.atomic.AtomicInteger; 51243830Sdimimport java.util.function.Consumer; 52243830Sdimimport java.util.logging.Level; 53243830Sdimimport jdk.internal.dynalink.support.NameCodec; 54243830Sdimimport jdk.nashorn.internal.codegen.ClassEmitter.Flag; 55243830Sdimimport jdk.nashorn.internal.codegen.types.Type; 56243830Sdimimport jdk.nashorn.internal.ir.FunctionNode; 57243830Sdimimport jdk.nashorn.internal.ir.Optimistic; 58243830Sdimimport jdk.nashorn.internal.ir.debug.ClassHistogramElement; 59243830Sdimimport jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; 60243830Sdimimport jdk.nashorn.internal.runtime.CodeInstaller; 61243830Sdimimport jdk.nashorn.internal.runtime.Context; 62243830Sdimimport jdk.nashorn.internal.runtime.FunctionInitializer; 63243830Sdimimport jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 64243830Sdimimport jdk.nashorn.internal.runtime.ScriptEnvironment; 65218887Sdimimport jdk.nashorn.internal.runtime.ScriptObject; 66218887Sdimimport jdk.nashorn.internal.runtime.Source; 67218887Sdimimport jdk.nashorn.internal.runtime.logging.DebugLogger; 68218887Sdimimport jdk.nashorn.internal.runtime.logging.Loggable; 69218887Sdimimport jdk.nashorn.internal.runtime.logging.Logger; 70218887Sdim 71218887Sdim/** 72218887Sdim * Responsible for converting JavaScripts to java byte code. Main entry 73218887Sdim * point for code generator. The compiler may also install classes given some 74218887Sdim * predefined Code installation policy, given to it at construction time. 75218887Sdim * @see CodeInstaller 76218887Sdim */ 77218887Sdim@Logger(name="compiler") 78218887Sdimpublic final class Compiler implements Loggable { 79218887Sdim 80218887Sdim /** Name of the scripts package */ 81218887Sdim public static final String SCRIPTS_PACKAGE = "jdk/nashorn/internal/scripts"; 82218887Sdim 83218887Sdim /** Name of the objects package */ 84218887Sdim public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; 85218887Sdim 86218887Sdim private final ScriptEnvironment env; 87226633Sdim 88218887Sdim private final Source source; 89218887Sdim 90218887Sdim private final String sourceName; 91218887Sdim 92218887Sdim private final boolean optimistic; 93218887Sdim 94218887Sdim private final Map<String, byte[]> bytecode; 95218887Sdim 96218887Sdim private final Set<CompileUnit> compileUnits; 97218887Sdim 98218887Sdim private final ConstantData constantData; 99218887Sdim 100218887Sdim private final CodeInstaller<ScriptEnvironment> installer; 101218887Sdim 102218887Sdim /** logger for compiler, trampolines, splits and related code generation events 103218887Sdim * that affect classes */ 104251662Sdim private final DebugLogger log; 105251662Sdim 106234353Sdim private final Context context; 107234353Sdim 108234353Sdim private final TypeMap types; 109234353Sdim 110234353Sdim // Runtime scope in effect at the time of the compilation. Used to evaluate types of expressions and prevent overly 111234353Sdim // optimistic assumptions (which will lead to unnecessary deoptimizing recompilations). 112234353Sdim private final TypeEvaluator typeEvaluator; 113234353Sdim 114234353Sdim private final boolean strict; 115251662Sdim 116251662Sdim private final boolean onDemand; 117251662Sdim 118251662Sdim /** 119234353Sdim * If this is a recompilation, this is how we pass in the invalidations, e.g. programPoint=17, Type == int means 120234353Sdim * that using whatever was at program point 17 as an int failed. 121234353Sdim */ 122234353Sdim private final Map<Integer, Type> invalidatedProgramPoints; 123234353Sdim 124218887Sdim /** 125226633Sdim * Descriptor of the location where we write the type information after compilation. 126218887Sdim */ 127218887Sdim private final Object typeInformationFile; 128218887Sdim 129234353Sdim /** 130218887Sdim * Compile unit name of first compile unit - this prefix will be used for all 131226633Sdim * classes that a compilation generates. 132234353Sdim */ 133218887Sdim private final String firstCompileUnitName; 134249423Sdim 135218887Sdim /** 136218887Sdim * Contains the program point that should be used as the continuation entry point, as well as all previous 137218887Sdim * continuation entry points executed as part of a single logical invocation of the function. In practical terms, if 138218887Sdim * we execute a rest-of method from the program point 17, but then we hit deoptimization again during it at program 139218887Sdim * point 42, and execute a rest-of method from the program point 42, and then we hit deoptimization again at program 140234353Sdim * point 57 and are compiling a rest-of method for it, the values in the array will be [57, 42, 17]. This is only 141226633Sdim * set when compiling a rest-of method. If this method is a rest-of for a non-rest-of method, the array will have 142226633Sdim * one element. If it is a rest-of for a rest-of, the array will have two elements, and so on. 143218887Sdim */ 144218887Sdim private final int[] continuationEntryPoints; 145218887Sdim 146218887Sdim /** 147243830Sdim * ScriptFunction data for what is being compile, where applicable. 148243830Sdim * TODO: make this immutable, propagate it through the CompilationPhases 149243830Sdim */ 150243830Sdim private RecompilableScriptFunctionData compiledFunction; 151243830Sdim 152243830Sdim /** 153243830Sdim * Compilation phases that a compilation goes through 154243830Sdim */ 155243830Sdim public static class CompilationPhases implements Iterable<CompilationPhase> { 156243830Sdim 157243830Sdim /** Singleton that describes a standard eager compilation - this includes code installation */ 158243830Sdim public final static CompilationPhases COMPILE_ALL = new CompilationPhases( 159243830Sdim "Compile all", 160243830Sdim new CompilationPhase[] { 161243830Sdim CompilationPhase.CONSTANT_FOLDING_PHASE, 162243830Sdim CompilationPhase.LOWERING_PHASE, 163243830Sdim CompilationPhase.PROGRAM_POINT_PHASE, 164226633Sdim CompilationPhase.TRANSFORM_BUILTINS_PHASE, 165226633Sdim CompilationPhase.SPLITTING_PHASE, 166218887Sdim CompilationPhase.SYMBOL_ASSIGNMENT_PHASE, 167218887Sdim CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE, 168218887Sdim CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE, 169218887Sdim CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, 170218887Sdim CompilationPhase.BYTECODE_GENERATION_PHASE, 171218887Sdim CompilationPhase.INSTALL_PHASE 172218887Sdim }); 173218887Sdim 174218887Sdim /** Compile all for a rest of method */ 175218887Sdim public final static CompilationPhases COMPILE_ALL_RESTOF = 176218887Sdim COMPILE_ALL.setDescription("Compile all, rest of").addAfter(CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE, CompilationPhase.REUSE_COMPILE_UNITS_PHASE); 177218887Sdim 178218887Sdim /** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */ 179234353Sdim public final static CompilationPhases COMPILE_ALL_NO_INSTALL = 180226633Sdim COMPILE_ALL. 181226633Sdim removeLast(). 182218887Sdim setDescription("Compile without install"); 183218887Sdim 184218887Sdim /** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */ 185218887Sdim public final static CompilationPhases COMPILE_UPTO_BYTECODE = 186226633Sdim COMPILE_ALL. 187226633Sdim removeLast(). 188218887Sdim removeLast(). 189218887Sdim setDescription("Compile upto bytecode"); 190218887Sdim 191218887Sdim /** 192218887Sdim * Singleton that describes back end of method generation, given that we have generated the normal 193218887Sdim * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE} 194226633Sdim */ 195218887Sdim public final static CompilationPhases COMPILE_FROM_BYTECODE = new CompilationPhases( 196218887Sdim "Generate bytecode and install", 197218887Sdim new CompilationPhase[] { 198218887Sdim CompilationPhase.BYTECODE_GENERATION_PHASE, 199218887Sdim CompilationPhase.INSTALL_PHASE 200218887Sdim }); 201218887Sdim 202218887Sdim /** 203218887Sdim * Singleton that describes restOf method generation, given that we have generated the normal 204234353Sdim * method up to CodeGenerator as in {@link CompilationPhases#COMPILE_UPTO_BYTECODE} 205218887Sdim */ 206218887Sdim public final static CompilationPhases COMPILE_FROM_BYTECODE_RESTOF = 207226633Sdim COMPILE_FROM_BYTECODE. 208218887Sdim addFirst(CompilationPhase.REUSE_COMPILE_UNITS_PHASE). 209226633Sdim setDescription("Generate bytecode and install - RestOf method"); 210218887Sdim 211218887Sdim private final List<CompilationPhase> phases; 212218887Sdim 213218887Sdim private final String desc; 214218887Sdim 215218887Sdim private CompilationPhases(final String desc, final CompilationPhase... phases) { 216218887Sdim this.desc = desc; 217218887Sdim 218243830Sdim final List<CompilationPhase> newPhases = new LinkedList<>(); 219226633Sdim newPhases.addAll(Arrays.asList(phases)); 220226633Sdim this.phases = Collections.unmodifiableList(newPhases); 221226633Sdim } 222226633Sdim 223226633Sdim @Override 224226633Sdim public String toString() { 225218887Sdim return "'" + desc + "' " + phases.toString(); 226218887Sdim } 227226633Sdim 228226633Sdim private CompilationPhases setDescription(final String desc) { 229226633Sdim return new CompilationPhases(desc, phases.toArray(new CompilationPhase[phases.size()])); 230226633Sdim } 231218887Sdim 232218887Sdim private CompilationPhases removeLast() { 233226633Sdim final LinkedList<CompilationPhase> list = new LinkedList<>(phases); 234218887Sdim list.removeLast(); 235218887Sdim return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 236218887Sdim } 237226633Sdim 238226633Sdim private CompilationPhases addFirst(final CompilationPhase phase) { 239218887Sdim if (phases.contains(phase)) { 240218887Sdim return this; 241218887Sdim } 242218887Sdim final LinkedList<CompilationPhase> list = new LinkedList<>(phases); 243226633Sdim list.addFirst(phase); 244218887Sdim return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 245218887Sdim } 246218887Sdim 247218887Sdim private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) { 248218887Sdim final LinkedList<CompilationPhase> list = new LinkedList<>(); 249218887Sdim for (final CompilationPhase p : phases) { 250218887Sdim list.add(p); 251218887Sdim if (p == phase) { 252218887Sdim list.add(newPhase); 253218887Sdim } 254218887Sdim } 255218887Sdim return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()])); 256226633Sdim } 257226633Sdim 258218887Sdim boolean contains(final CompilationPhase phase) { 259218887Sdim return phases.contains(phase); 260218887Sdim } 261218887Sdim 262218887Sdim @Override 263218887Sdim public Iterator<CompilationPhase> iterator() { 264218887Sdim return phases.iterator(); 265218887Sdim } 266218887Sdim 267226633Sdim boolean isRestOfCompilation() { 268218887Sdim return this == COMPILE_ALL_RESTOF || this == COMPILE_FROM_BYTECODE_RESTOF; 269218887Sdim } 270226633Sdim 271218887Sdim String getDesc() { 272218887Sdim return desc; 273218887Sdim } 274251662Sdim 275251662Sdim String toString(final String prefix) { 276251662Sdim final StringBuilder sb = new StringBuilder(); 277234353Sdim for (final CompilationPhase phase : phases) { 278218887Sdim sb.append(prefix).append(phase).append('\n'); 279218887Sdim } 280234353Sdim return sb.toString(); 281218887Sdim } 282218887Sdim } 283218887Sdim 284218887Sdim /** 285218887Sdim * This array contains names that need to be reserved at the start 286234353Sdim * of a compile, to avoid conflict with variable names later introduced. 287218887Sdim * See {@link CompilerConstants} for special names used for structures 288218887Sdim * during a compile. 289218887Sdim */ 290218887Sdim private static String[] RESERVED_NAMES = { 291218887Sdim SCOPE.symbolName(), 292218887Sdim THIS.symbolName(), 293218887Sdim RETURN.symbolName(), 294218887Sdim CALLEE.symbolName(), 295226633Sdim VARARGS.symbolName(), 296218887Sdim ARGUMENTS.symbolName() 297218887Sdim }; 298226633Sdim 299218887Sdim // per instance 300218887Sdim private final int compilationId = COMPILATION_ID.getAndIncrement(); 301218887Sdim 302226633Sdim // per instance 303218887Sdim private final AtomicInteger nextCompileUnitId = new AtomicInteger(0); 304218887Sdim 305218887Sdim private static final AtomicInteger COMPILATION_ID = new AtomicInteger(0); 306226633Sdim 307218887Sdim /** 308226633Sdim * Constructor 309226633Sdim * 310218887Sdim * @param context context 311226633Sdim * @param env script environment 312218887Sdim * @param installer code installer 313218887Sdim * @param source source to compile 314226633Sdim * @param isStrict is this a strict compilation 315218887Sdim */ 316218887Sdim public Compiler( 317226633Sdim final Context context, 318218887Sdim final ScriptEnvironment env, 319218887Sdim final CodeInstaller<ScriptEnvironment> installer, 320218887Sdim final Source source, 321218887Sdim final boolean isStrict) { 322218887Sdim this(context, env, installer, source, isStrict, false, null, null, null, null, null, null); 323218887Sdim } 324218887Sdim 325218887Sdim /** 326218887Sdim * Constructor 327218887Sdim * 328234353Sdim * @param context context 329234353Sdim * @param env script environment 330234353Sdim * @param installer code installer 331224145Sdim * @param source source to compile 332224145Sdim * @param isStrict is this a strict compilation 333234353Sdim * @param isOnDemand is this an on demand compilation 334234353Sdim * @param compiledFunction compiled function, if any 335251662Sdim * @param types parameter and return value type information, if any is known 336234353Sdim * @param invalidatedProgramPoints invalidated program points for recompilation 337218887Sdim * @param typeInformationFile descriptor of the location where type information is persisted 338218887Sdim * @param continuationEntryPoints continuation entry points for restof method 339218887Sdim * @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator} 340218887Sdim */ 341218887Sdim public Compiler( 342218887Sdim final Context context, 343218887Sdim final ScriptEnvironment env, 344218887Sdim final CodeInstaller<ScriptEnvironment> installer, 345243830Sdim final Source source, 346218887Sdim final boolean isStrict, 347218887Sdim final boolean isOnDemand, 348218887Sdim final RecompilableScriptFunctionData compiledFunction, 349218887Sdim final TypeMap types, 350218887Sdim final Map<Integer, Type> invalidatedProgramPoints, 351218887Sdim final Object typeInformationFile, 352218887Sdim final int[] continuationEntryPoints, 353234353Sdim final ScriptObject runtimeScope) { 354218887Sdim this.context = context; 355218887Sdim this.env = env; 356234353Sdim this.installer = installer; 357234353Sdim this.constantData = new ConstantData(); 358234353Sdim this.compileUnits = CompileUnit.createCompileUnitSet(); 359218887Sdim this.bytecode = new LinkedHashMap<>(); 360218887Sdim this.log = initLogger(context); 361218887Sdim this.source = source; 362218887Sdim this.sourceName = FunctionNode.getSourceName(source); 363218887Sdim this.onDemand = isOnDemand; 364218887Sdim this.compiledFunction = compiledFunction; 365218887Sdim this.types = types; 366218887Sdim this.invalidatedProgramPoints = invalidatedProgramPoints == null ? new HashMap<Integer, Type>() : invalidatedProgramPoints; 367218887Sdim this.typeInformationFile = typeInformationFile; 368218887Sdim this.continuationEntryPoints = continuationEntryPoints == null ? null: continuationEntryPoints.clone(); 369218887Sdim this.typeEvaluator = new TypeEvaluator(this, runtimeScope); 370218887Sdim this.firstCompileUnitName = firstCompileUnitName(); 371218887Sdim this.strict = isStrict; 372218887Sdim 373218887Sdim this.optimistic = env._optimistic_types; 374218887Sdim } 375218887Sdim 376218887Sdim private static String safeSourceName(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final Source source) { 377226633Sdim String baseName = new File(source.getName()).getName(); 378226633Sdim 379226633Sdim final int index = baseName.lastIndexOf(".js"); 380218887Sdim if (index != -1) { 381218887Sdim baseName = baseName.substring(0, index); 382218887Sdim } 383218887Sdim 384218887Sdim baseName = baseName.replace('.', '_').replace('-', '_'); 385218887Sdim if (!env._loader_per_compile) { 386218887Sdim baseName = baseName + installer.getUniqueScriptId(); 387218887Sdim } 388218887Sdim 389218887Sdim final String mangled = NameCodec.encode(baseName); 390218887Sdim return mangled != null ? mangled : baseName; 391218887Sdim } 392218887Sdim 393218887Sdim private String firstCompileUnitName() { 394218887Sdim final StringBuilder sb = new StringBuilder(SCRIPTS_PACKAGE). 395218887Sdim append('/'). 396218887Sdim append(CompilerConstants.DEFAULT_SCRIPT_NAME.symbolName()). 397218887Sdim append('$'); 398218887Sdim 399218887Sdim if (isOnDemandCompilation()) { 400218887Sdim sb.append(RecompilableScriptFunctionData.RECOMPILATION_PREFIX); 401226633Sdim } 402218887Sdim 403218887Sdim if (compilationId > 0) { 404218887Sdim sb.append(compilationId).append('$'); 405218887Sdim } 406226633Sdim 407218887Sdim if (types != null && compiledFunction.getFunctionNodeId() > 0) { 408226633Sdim sb.append(compiledFunction.getFunctionNodeId()); 409226633Sdim final Type[] paramTypes = types.getParameterTypes(compiledFunction.getFunctionNodeId()); 410218887Sdim for (final Type t : paramTypes) { 411218887Sdim sb.append(Type.getShortSignatureDescriptor(t)); 412218887Sdim } 413218887Sdim sb.append('$'); 414218887Sdim } 415218887Sdim 416218887Sdim sb.append(Compiler.safeSourceName(env, installer, source)); 417218887Sdim 418218887Sdim return sb.toString(); 419218887Sdim } 420218887Sdim 421218887Sdim void declareLocalSymbol(final String symbolName) { 422218887Sdim typeEvaluator.declareLocalSymbol(symbolName); 423218887Sdim } 424221345Sdim 425218887Sdim void setData(final RecompilableScriptFunctionData data) { 426218887Sdim assert this.compiledFunction == null : data; 427218887Sdim this.compiledFunction = data; 428249423Sdim } 429249423Sdim 430249423Sdim @Override 431249423Sdim public DebugLogger getLogger() { 432249423Sdim return log; 433249423Sdim } 434249423Sdim 435249423Sdim @Override 436249423Sdim public DebugLogger initLogger(final Context ctxt) { 437226633Sdim return ctxt.getLogger(this.getClass(), new Consumer<DebugLogger>() { 438218887Sdim @Override 439234353Sdim public void accept(final DebugLogger newLogger) { 440218887Sdim if (!Compiler.this.getScriptEnvironment()._lazy_compilation) { 441218887Sdim newLogger.warning("WARNING: Running with lazy compilation switched off. This is not a default setting."); 442218887Sdim } 443226633Sdim } 444226633Sdim }); 445218887Sdim } 446218887Sdim 447218887Sdim ScriptEnvironment getScriptEnvironment() { 448218887Sdim return env; 449218887Sdim } 450218887Sdim 451218887Sdim boolean isOnDemandCompilation() { 452218887Sdim return onDemand; 453 } 454 455 boolean useOptimisticTypes() { 456 return optimistic; 457 } 458 459 Context getContext() { 460 return context; 461 } 462 463 Type getOptimisticType(final Optimistic node) { 464 return typeEvaluator.getOptimisticType(node); 465 } 466 467 void addInvalidatedProgramPoint(final int programPoint, final Type type) { 468 invalidatedProgramPoints.put(programPoint, type); 469 } 470 471 472 /** 473 * Returns a copy of this compiler's current mapping of invalidated optimistic program points to their types. The 474 * copy is not live with regard to changes in state in this compiler instance, and is mutable. 475 * @return a copy of this compiler's current mapping of invalidated optimistic program points to their types. 476 */ 477 public Map<Integer, Type> getInvalidatedProgramPoints() { 478 return invalidatedProgramPoints == null ? null : new TreeMap<>(invalidatedProgramPoints); 479 } 480 481 TypeMap getTypeMap() { 482 return types; 483 } 484 485 MethodType getCallSiteType(final FunctionNode fn) { 486 if (types == null || !isOnDemandCompilation()) { 487 return null; 488 } 489 return types.getCallSiteType(fn); 490 } 491 492 Type getParamType(final FunctionNode fn, final int pos) { 493 return types == null ? null : types.get(fn, pos); 494 } 495 496 /** 497 * Do a compilation job 498 * 499 * @param functionNode function node to compile 500 * @param phases phases of compilation transforms to apply to function 501 502 * @return transformed function 503 * 504 * @throws CompilationException if error occurs during compilation 505 */ 506 public FunctionNode compile(final FunctionNode functionNode, final CompilationPhases phases) throws CompilationException { 507 508 log.finest("Starting compile job for ", DebugLogger.quote(functionNode.getName()), " phases=", quote(phases.getDesc())); 509 log.indent(); 510 511 final String name = DebugLogger.quote(functionNode.getName()); 512 513 FunctionNode newFunctionNode = functionNode; 514 515 for (final String reservedName : RESERVED_NAMES) { 516 newFunctionNode.uniqueName(reservedName); 517 } 518 519 final boolean info = log.levelFinerThanOrEqual(Level.INFO); 520 521 final DebugLogger timeLogger = env.isTimingEnabled() ? env._timing.getLogger() : null; 522 523 long time = 0L; 524 525 for (final CompilationPhase phase : phases) { 526 log.fine(phase, " starting for ", quote(name)); 527 newFunctionNode = phase.apply(this, phases, newFunctionNode); 528 log.fine(phase, " done for function ", quote(name)); 529 530 if (env._print_mem_usage) { 531 printMemoryUsage(functionNode, phase.toString()); 532 } 533 534 time += (env.isTimingEnabled() ? phase.getEndTime() - phase.getStartTime() : 0L); 535 } 536 537 if (typeInformationFile != null && !phases.isRestOfCompilation()) { 538 OptimisticTypesPersistence.store(typeInformationFile, invalidatedProgramPoints); 539 } 540 541 log.unindent(); 542 543 if (info) { 544 final StringBuilder sb = new StringBuilder(); 545 sb.append("Compile job for ").append(newFunctionNode.getSource()).append(':').append(quote(newFunctionNode.getName())).append(" finished"); 546 if (time > 0L && timeLogger != null) { 547 assert env.isTimingEnabled(); 548 sb.append(" in ").append(time).append(" ms"); 549 } 550 log.info(sb); 551 } 552 553 return newFunctionNode; 554 } 555 556 Source getSource() { 557 return source; 558 } 559 560 Map<String, byte[]> getBytecode() { 561 return Collections.unmodifiableMap(bytecode); 562 } 563 564 /** 565 * Reset bytecode cache for compiler reuse. 566 */ 567 void clearBytecode() { 568 bytecode.clear(); 569 } 570 571 CompileUnit getFirstCompileUnit() { 572 assert !compileUnits.isEmpty(); 573 return compileUnits.iterator().next(); 574 } 575 576 Set<CompileUnit> getCompileUnits() { 577 return compileUnits; 578 } 579 580 ConstantData getConstantData() { 581 return constantData; 582 } 583 584 CodeInstaller<ScriptEnvironment> getCodeInstaller() { 585 return installer; 586 } 587 588 void addClass(final String name, final byte[] code) { 589 bytecode.put(name, code); 590 } 591 592 String nextCompileUnitName() { 593 final StringBuilder sb = new StringBuilder(firstCompileUnitName); 594 final int cuid = nextCompileUnitId.getAndIncrement(); 595 if (cuid > 0) { 596 sb.append("$cu").append(cuid); 597 } 598 599 return sb.toString(); 600 } 601 602 Map<Integer, FunctionInitializer> functionInitializers; 603 604 void addFunctionInitializer(final RecompilableScriptFunctionData functionData, final FunctionNode functionNode) { 605 if (functionInitializers == null) { 606 functionInitializers = new HashMap<>(); 607 } 608 if (!functionInitializers.containsKey(functionData)) { 609 functionInitializers.put(functionData.getFunctionNodeId(), new FunctionInitializer(functionNode)); 610 } 611 } 612 613 Map<Integer, FunctionInitializer> getFunctionInitializers() { 614 return functionInitializers; 615 } 616 617 /** 618 * Persist current compilation with the given {@code cacheKey}. 619 * @param cacheKey cache key 620 * @param functionNode function node 621 */ 622 public void persistClassInfo(final String cacheKey, final FunctionNode functionNode) { 623 if (cacheKey != null && env._persistent_cache) { 624 Map<Integer, FunctionInitializer> initializers; 625 // If this is an on-demand compilation create a function initializer for the function being compiled. 626 // Otherwise use function initializer map generated by codegen. 627 if (functionInitializers == null) { 628 initializers = new HashMap<>(); 629 final FunctionInitializer initializer = new FunctionInitializer(functionNode, getInvalidatedProgramPoints()); 630 initializers.put(functionNode.getId(), initializer); 631 } else { 632 initializers = functionInitializers; 633 } 634 final String mainClassName = getFirstCompileUnit().getUnitClassName(); 635 installer.storeScript(cacheKey, source, mainClassName, bytecode, initializers, constantData.toArray(), compilationId); 636 } 637 } 638 639 /** 640 * Make sure the next compilation id is greater than {@code value}. 641 * @param value compilation id value 642 */ 643 public static void updateCompilationId(final int value) { 644 if (value >= COMPILATION_ID.get()) { 645 COMPILATION_ID.set(value + 1); 646 } 647 } 648 649 CompileUnit addCompileUnit(final long initialWeight) { 650 final CompileUnit compileUnit = createCompileUnit(initialWeight); 651 compileUnits.add(compileUnit); 652 log.fine("Added compile unit ", compileUnit); 653 return compileUnit; 654 } 655 656 CompileUnit createCompileUnit(final String unitClassName, final long initialWeight) { 657 final ClassEmitter classEmitter = new ClassEmitter(context, sourceName, unitClassName, isStrict()); 658 final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); 659 660 classEmitter.begin(); 661 662 final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE)); 663 initMethod.begin(); 664 initMethod.load(Type.OBJECT, 0); 665 initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class); 666 initMethod.returnVoid(); 667 initMethod.end(); 668 669 return compileUnit; 670 } 671 672 private CompileUnit createCompileUnit(final long initialWeight) { 673 return createCompileUnit(nextCompileUnitName(), initialWeight); 674 } 675 676 boolean isStrict() { 677 return strict; 678 } 679 680 void replaceCompileUnits(final Set<CompileUnit> newUnits) { 681 compileUnits.clear(); 682 compileUnits.addAll(newUnits); 683 } 684 685 CompileUnit findUnit(final long weight) { 686 for (final CompileUnit unit : compileUnits) { 687 if (unit.canHold(weight)) { 688 unit.addWeight(weight); 689 return unit; 690 } 691 } 692 693 return addCompileUnit(weight); 694 } 695 696 /** 697 * Convert a package/class name to a binary name. 698 * 699 * @param name Package/class name. 700 * @return Binary name. 701 */ 702 public static String binaryName(final String name) { 703 return name.replace('/', '.'); 704 } 705 706 RecompilableScriptFunctionData getProgram() { 707 if (compiledFunction == null) { 708 return null; 709 } 710 return compiledFunction.getProgram(); 711 } 712 713 RecompilableScriptFunctionData getScriptFunctionData(final int functionId) { 714 return compiledFunction == null ? null : compiledFunction.getScriptFunctionData(functionId); 715 } 716 717 boolean isGlobalSymbol(final FunctionNode fn, final String name) { 718 return getScriptFunctionData(fn.getId()).isGlobalSymbol(fn, name); 719 } 720 721 int[] getContinuationEntryPoints() { 722 return continuationEntryPoints; 723 } 724 725 Type getInvalidatedProgramPointType(final int programPoint) { 726 return invalidatedProgramPoints.get(programPoint); 727 } 728 729 private void printMemoryUsage(final FunctionNode functionNode, final String phaseName) { 730 if (!log.isEnabled()) { 731 return; 732 } 733 734 log.info(phaseName, "finished. Doing IR size calculation..."); 735 736 final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification()); 737 osc.calculateObjectSize(functionNode); 738 739 final List<ClassHistogramElement> list = osc.getClassHistogram(); 740 final StringBuilder sb = new StringBuilder(); 741 final long totalSize = osc.calculateObjectSize(functionNode); 742 743 sb.append(phaseName). 744 append(" Total size = "). 745 append(totalSize / 1024 / 1024). 746 append("MB"); 747 log.info(sb); 748 749 Collections.sort(list, new Comparator<ClassHistogramElement>() { 750 @Override 751 public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { 752 final long diff = o1.getBytes() - o2.getBytes(); 753 if (diff < 0) { 754 return 1; 755 } else if (diff > 0) { 756 return -1; 757 } else { 758 return 0; 759 } 760 } 761 }); 762 for (final ClassHistogramElement e : list) { 763 final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances()); 764 log.info(line); 765 if (e.getBytes() < totalSize / 200) { 766 log.info(" ..."); 767 break; // never mind, so little memory anyway 768 } 769 } 770 } 771} 772