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