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 
  26 package jdk.nashorn.internal.codegen;
  27 
  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.CONSTANTS;
  31 import static jdk.nashorn.internal.codegen.CompilerConstants.DEFAULT_SCRIPT_NAME;
  32 import static jdk.nashorn.internal.codegen.CompilerConstants.LAZY;
  33 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
  34 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
  35 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
  36 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
  37 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
  38 
  39 import java.io.File;
  40 import java.lang.reflect.Field;
  41 import java.security.AccessController;
  42 import java.security.PrivilegedActionException;
  43 import java.security.PrivilegedExceptionAction;
  44 import java.util.Arrays;
  45 import java.util.Collections;
  46 import java.util.Comparator;
  47 import java.util.EnumSet;
  48 import java.util.HashMap;
  49 import java.util.LinkedHashMap;
  50 import java.util.LinkedList;
  51 import java.util.List;
  52 import java.util.Map;
  53 import java.util.Map.Entry;
  54 import java.util.Set;
  55 import java.util.TreeSet;
  56 import java.util.logging.Level;
  57 import jdk.internal.dynalink.support.NameCodec;
  58 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
  59 import jdk.nashorn.internal.codegen.types.Type;
  60 import jdk.nashorn.internal.ir.FunctionNode;
  61 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
  62 import jdk.nashorn.internal.ir.TemporarySymbols;
  63 import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
  64 import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
  65 import jdk.nashorn.internal.runtime.CodeCache;
  66 import jdk.nashorn.internal.runtime.CodeInstaller;
  67 import jdk.nashorn.internal.runtime.DebugLogger;
  68 import jdk.nashorn.internal.runtime.PersistentCodeCache;
  69 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
  70 import jdk.nashorn.internal.runtime.ScriptEnvironment;
  71 import jdk.nashorn.internal.runtime.Source;
  72 import jdk.nashorn.internal.runtime.Timing;
  73 import jdk.nashorn.internal.runtime.options.Options;
  74 
  75 /**
  76  * Responsible for converting JavaScripts to java byte code. Main entry
  77  * point for code generator. The compiler may also install classes given some
  78  * predefined Code installation policy, given to it at construction time.
  79  * @see CodeInstaller
  80  */
  81 public final class Compiler {
  82 
  83     /** Name of the scripts package */
  84     public static final String SCRIPTS_PACKAGE = "jdk/nashorn/internal/scripts";
  85 
  86     /** Name of the objects package */
  87     public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
  88 
  89     private Source source;
  90 
  91     private String sourceName;
  92 
  93     private final Map<String, byte[]> bytecode;
  94 
  95     private final Set<CompileUnit> compileUnits;
  96 
  97     private final ConstantData constantData;
  98 
  99     private final CompilationSequence sequence;
 100 
 101     private final ScriptEnvironment env;
 102 
 103     private String scriptName;
 104 
 105     private boolean strict;
 106 
 107     private final CodeInstaller<ScriptEnvironment> installer;
 108 
 109     private final TemporarySymbols temporarySymbols = new TemporarySymbols();
 110 
 111     /** logger for compiler, trampolines, splits and related code generation events
 112      *  that affect classes */
 113     public static final DebugLogger LOG = new DebugLogger("compiler");
 114 
 115     /**
 116      * This array contains names that need to be reserved at the start
 117      * of a compile, to avoid conflict with variable names later introduced.
 118      * See {@link CompilerConstants} for special names used for structures
 119      * during a compile.
 120      */
 121     private static String[] RESERVED_NAMES = {
 122         SCOPE.symbolName(),
 123         THIS.symbolName(),
 124         RETURN.symbolName(),
 125         CALLEE.symbolName(),
 126         VARARGS.symbolName(),
 127         ARGUMENTS.symbolName()
 128     };
 129 
 130     /**
 131      * This class makes it possible to do your own compilation sequence
 132      * from the code generation package. There are predefined compilation
 133      * sequences already
 134      */
 135     @SuppressWarnings("serial")
 136     static class CompilationSequence extends LinkedList<CompilationPhase> {
 137 
 138         CompilationSequence(final CompilationPhase... phases) {
 139             super(Arrays.asList(phases));
 140         }
 141 
 142         CompilationSequence(final CompilationSequence sequence) {
 143             this(sequence.toArray(new CompilationPhase[sequence.size()]));
 144         }
 145 
 146         CompilationSequence insertAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
 147             final CompilationSequence newSeq = new CompilationSequence();
 148             for (final CompilationPhase elem : this) {
 149                 newSeq.add(phase);
 150                 if (elem.equals(phase)) {
 151                     newSeq.add(newPhase);
 152                 }
 153             }
 154             assert newSeq.contains(newPhase);
 155             return newSeq;
 156         }
 157 
 158         CompilationSequence insertBefore(final CompilationPhase phase, final CompilationPhase newPhase) {
 159             final CompilationSequence newSeq = new CompilationSequence();
 160             for (final CompilationPhase elem : this) {
 161                 if (elem.equals(phase)) {
 162                     newSeq.add(newPhase);
 163                 }
 164                 newSeq.add(phase);
 165             }
 166             assert newSeq.contains(newPhase);
 167             return newSeq;
 168         }
 169 
 170         CompilationSequence insertFirst(final CompilationPhase phase) {
 171             final CompilationSequence newSeq = new CompilationSequence(this);
 172             newSeq.addFirst(phase);
 173             return newSeq;
 174         }
 175 
 176         CompilationSequence insertLast(final CompilationPhase phase) {
 177             final CompilationSequence newSeq = new CompilationSequence(this);
 178             newSeq.addLast(phase);
 179             return newSeq;
 180         }
 181     }
 182 
 183     /**
 184      * Environment information known to the compile, e.g. params
 185      */
 186     public static class Hints {
 187         private final Type[] paramTypes;
 188 
 189         /** singleton empty hints */
 190         public static final Hints EMPTY = new Hints();
 191 
 192         private Hints() {
 193             this.paramTypes = null;
 194         }
 195 
 196         /**
 197          * Constructor
 198          * @param paramTypes known parameter types for this callsite
 199          */
 200         public Hints(final Type[] paramTypes) {
 201             this.paramTypes = paramTypes;
 202         }
 203 
 204         /**
 205          * Get the parameter type for this parameter position, or
 206          * null if now known
 207          * @param pos position
 208          * @return parameter type for this callsite if known
 209          */
 210         public Type getParameterType(final int pos) {
 211             if (paramTypes != null && pos < paramTypes.length) {
 212                 return paramTypes[pos];
 213             }
 214             return null;
 215         }
 216     }
 217 
 218     /**
 219      * Standard (non-lazy) compilation, that basically will take an entire script
 220      * and JIT it at once. This can lead to long startup time and fewer type
 221      * specializations
 222      */
 223     final static CompilationSequence SEQUENCE_EAGER = new CompilationSequence(
 224         CompilationPhase.CONSTANT_FOLDING_PHASE,
 225         CompilationPhase.LOWERING_PHASE,
 226         CompilationPhase.ATTRIBUTION_PHASE,
 227         CompilationPhase.RANGE_ANALYSIS_PHASE,
 228         CompilationPhase.SPLITTING_PHASE,
 229         CompilationPhase.TYPE_FINALIZATION_PHASE,
 230         CompilationPhase.BYTECODE_GENERATION_PHASE);
 231 
 232     final static CompilationSequence SEQUENCE_LAZY =
 233         SEQUENCE_EAGER.insertFirst(CompilationPhase.LAZY_INITIALIZATION_PHASE);
 234 
 235     private static CompilationSequence sequence(final boolean lazy) {
 236         return lazy ? SEQUENCE_LAZY : SEQUENCE_EAGER;
 237     }
 238 
 239     boolean isLazy() {
 240         return sequence == SEQUENCE_LAZY;
 241     }
 242 
 243     private static String lazyTag(final FunctionNode functionNode) {
 244         if (functionNode.isLazy()) {
 245             return '$' + LAZY.symbolName() + '$' + functionNode.getName();
 246         }
 247         return "";
 248     }
 249 
 250     /**
 251      * Constructor
 252      *
 253      * @param env          script environment
 254      * @param installer    code installer
 255      * @param sequence     {@link Compiler.CompilationSequence} of {@link CompilationPhase}s to apply as this compilation
 256      * @param strict       should this compilation use strict mode semantics
 257      */
 258     //TODO support an array of FunctionNodes for batch lazy compilation
 259     Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) {
 260         this.env           = env;
 261         this.sequence      = sequence;
 262         this.installer     = installer;
 263         this.constantData  = new ConstantData();
 264         this.compileUnits  = new TreeSet<>();
 265         this.bytecode      = new LinkedHashMap<>();
 266     }
 267 
 268     private void initCompiler(final FunctionNode functionNode) {
 269         this.strict        = strict || functionNode.isStrict();
 270         final StringBuilder sb = new StringBuilder();
 271         sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
 272                 append('$').
 273                 append(safeSourceName(functionNode.getSource()));
 274         this.source = functionNode.getSource();
 275         this.sourceName = functionNode.getSourceName();
 276         this.scriptName = sb.toString();
 277     }
 278 
 279     /**
 280      * Constructor
 281      *
 282      * @param installer    code installer
 283      * @param strict       should this compilation use strict mode semantics
 284      */
 285     public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) {
 286         this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict);
 287     }
 288 
 289     /**
 290      * Constructor - compilation will use the same strict semantics as in script environment
 291      *
 292      * @param installer    code installer
 293      */
 294     public Compiler(final CodeInstaller<ScriptEnvironment> installer) {
 295         this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
 296     }
 297 
 298     /**
 299      * Constructor - compilation needs no installer, but uses a script environment
 300      * Used in "compile only" scenarios
 301      * @param env a script environment
 302      */
 303     public Compiler(final ScriptEnvironment env) {
 304         this(env, null, sequence(env._lazy_compilation), env._strict);
 305     }
 306 
 307     private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
 308         LOG.info(phaseName + " finished. Doing IR size calculation...");
 309 
 310         final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
 311         osc.calculateObjectSize(functionNode);
 312 
 313         final List<ClassHistogramElement> list = osc.getClassHistogram();
 314 
 315         final StringBuilder sb = new StringBuilder();
 316         final long totalSize = osc.calculateObjectSize(functionNode);
 317         sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
 318         LOG.info(sb);
 319 
 320         Collections.sort(list, new Comparator<ClassHistogramElement>() {
 321             @Override
 322             public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
 323                 final long diff = o1.getBytes() - o2.getBytes();
 324                 if (diff < 0) {
 325                     return 1;
 326                 } else if (diff > 0) {
 327                     return -1;
 328                 } else {
 329                     return 0;
 330                 }
 331             }
 332         });
 333         for (final ClassHistogramElement e : list) {
 334             final String line = String.format("    %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
 335             LOG.info(line);
 336             if (e.getBytes() < totalSize / 200) {
 337                 LOG.info("    ...");
 338                 break; // never mind, so little memory anyway
 339             }
 340         }
 341     }
 342 
 343     /**
 344      * Execute the compilation this Compiler was created with
 345      * @param functionNode function node to compile from its current state
 346      * @throws CompilationException if something goes wrong
 347      * @return function node that results from code transforms
 348      */
 349     public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
 350         FunctionNode newFunctionNode = functionNode;
 351 
 352         initCompiler(newFunctionNode); //TODO move this state into functionnode?
 353 
 354         for (final String reservedName : RESERVED_NAMES) {
 355             newFunctionNode.uniqueName(reservedName);
 356         }
 357 
 358         final boolean fine = !LOG.levelAbove(Level.FINE);
 359         final boolean info = !LOG.levelAbove(Level.INFO);
 360 
 361         long time = 0L;
 362 
 363         for (final CompilationPhase phase : sequence) {
 364             newFunctionNode = phase.apply(this, newFunctionNode);
 365 
 366             if (env._print_mem_usage) {
 367                 printMemoryUsage(phase.toString(), newFunctionNode);
 368             }
 369 
 370             final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
 371             time += duration;
 372 
 373             if (fine) {
 374                 final StringBuilder sb = new StringBuilder();
 375 
 376                 sb.append(phase.toString()).
 377                     append(" done for function '").
 378                     append(newFunctionNode.getName()).
 379                     append('\'');
 380 
 381                 if (duration > 0L) {
 382                     sb.append(" in ").
 383                         append(duration).
 384                         append(" ms ");
 385                 }
 386 
 387                 LOG.fine(sb);
 388             }
 389         }
 390 
 391         if (info) {
 392             final StringBuilder sb = new StringBuilder();
 393             sb.append("Compile job for '").
 394                 append(newFunctionNode.getSource()).
 395                 append(':').
 396                 append(newFunctionNode.getName()).
 397                 append("' finished");
 398 
 399             if (time > 0L) {
 400                 sb.append(" in ").
 401                     append(time).
 402                     append(" ms");
 403             }
 404 
 405             LOG.info(sb);
 406         }
 407 
 408         return newFunctionNode;
 409     }
 410 
 411     private Class<?> install(final String className, final byte[] code, final Object[] constants) {
 412         LOG.fine("Installing class ", className);
 413 
 414         final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
 415 
 416         try {
 417             // Need doPrivileged because these fields are private
 418             AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
 419                 @Override
 420                 public Void run() throws Exception {
 421                     //use reflection to write source and constants table to installed classes
 422                     final Field sourceField    = clazz.getDeclaredField(SOURCE.symbolName());
 423                     final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName());
 424                     sourceField.setAccessible(true);
 425                     constantsField.setAccessible(true);
 426                     sourceField.set(null, source);
 427                     constantsField.set(null, constants);
 428                     return null;
 429                 }
 430             });
 431         } catch (final PrivilegedActionException e) {
 432             throw new RuntimeException(e);
 433         }
 434 
 435         return clazz;
 436     }
 437 
 438     /**
 439      * Install compiled classes into a given loader
 440      * @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state
 441      * @return root script class - if there are several compile units they will also be installed
 442      */
 443     public Class<?> install(final FunctionNode functionNode) {
 444         final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
 445 
 446         assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
 447 
 448         final Map<String, Class<?>> installedClasses = new HashMap<>();
 449         final Object[] constants = getConstantData().toArray();
 450 
 451         final String   rootClassName = firstCompileUnitName();
 452         final byte[]   rootByteCode  = bytecode.get(rootClassName);
 453         final Class<?> rootClass     = install(rootClassName, rootByteCode, constants);
 454 
 455         final CodeCache codeCache = installer.getCodeCache();
 456         if (!isLazy() && codeCache != null) {
 457             try {
 458                 codeCache.putScript(source, rootClassName, bytecode, constants);
 459             } catch (Exception e) {
 460                 throw new RuntimeException(e);
 461             }
 462         }
 463 
 464         int length = rootByteCode.length;
 465 
 466         installedClasses.put(rootClassName, rootClass);
 467 
 468         for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
 469             final String className = entry.getKey();
 470             if (className.equals(rootClassName)) {
 471                 continue;
 472             }
 473             final byte[] code = entry.getValue();
 474             length += code.length;
 475 
 476             installedClasses.put(className, install(className, code, constants));
 477         }
 478 
 479         for (final CompileUnit unit : compileUnits) {
 480             unit.setCode(installedClasses.get(unit.getUnitClassName()));
 481         }
 482 
 483         final StringBuilder sb;
 484         if (LOG.isEnabled()) {
 485             sb = new StringBuilder();
 486             sb.append("Installed class '").
 487                 append(rootClass.getSimpleName()).
 488                 append('\'').
 489                 append(" bytes=").
 490                 append(length).
 491                 append('.');
 492             if (bytecode.size() > 1) {
 493                 sb.append(' ').append(bytecode.size()).append(" compile units.");
 494             }
 495         } else {
 496             sb = null;
 497         }
 498 
 499         if (Timing.isEnabled()) {
 500             final long duration = System.currentTimeMillis() - t0;
 501             Timing.accumulateTime("[Code Installation]", duration);
 502             if (sb != null) {
 503                 sb.append(" Install time: ").append(duration).append(" ms");
 504             }
 505         }
 506 
 507         if (sb != null) {
 508             LOG.fine(sb);
 509         }
 510 
 511         return rootClass;
 512     }
 513 
 514     /**
 515      * Install a previously compiled class from the code cache.
 516      *
 517      * @param cachedScript cached script containing class bytes and constants
 518      * @return main script class
 519      */
 520     public Class<?> install(final PersistentCodeCache.CachedScript cachedScript) {
 521         this.source = cachedScript.getSource();
 522 
 523         final Map<String, Class<?>> installedClasses = new HashMap<>();
 524         final Object[] constants = cachedScript.getConstants();
 525 
 526         final String   rootClassName = cachedScript.getMainClassName();
 527         final byte[]   rootByteCode  = cachedScript.getClassBytes().get(rootClassName);
 528         final Class<?> rootClass     = install(rootClassName, rootByteCode, constants);
 529 
 530         installedClasses.put(rootClassName, rootClass);
 531 
 532         for (final Entry<String, byte[]> entry : cachedScript.getClassBytes().entrySet()) {
 533             final String className = entry.getKey();
 534             if (className.equals(rootClassName)) {
 535                 continue;
 536             }
 537             final byte[] code = entry.getValue();
 538 
 539             installedClasses.put(className, install(className, code, constants));
 540         }
 541         for (Object constant : constants) {
 542             if (constant instanceof RecompilableScriptFunctionData) {
 543                 ((RecompilableScriptFunctionData) constant).setCodeAndSource(installedClasses, source);
 544             }
 545         }
 546 
 547         return rootClass;
 548     }
 549 
 550     Set<CompileUnit> getCompileUnits() {
 551         return compileUnits;
 552     }
 553 
 554     boolean getStrictMode() {
 555         return strict;
 556     }
 557 
 558     void setStrictMode(final boolean strict) {
 559         this.strict = strict;
 560     }
 561 
 562     ConstantData getConstantData() {
 563         return constantData;
 564     }
 565 
 566     CodeInstaller<ScriptEnvironment> getCodeInstaller() {
 567         return installer;
 568     }
 569 
 570     TemporarySymbols getTemporarySymbols() {
 571         return temporarySymbols;
 572     }
 573 
 574     void addClass(final String name, final byte[] code) {
 575         bytecode.put(name, code);
 576     }
 577 
 578     ScriptEnvironment getEnv() {
 579         return this.env;
 580     }
 581 
 582     private String safeSourceName(final Source src) {
 583         String baseName = new File(src.getName()).getName();
 584 
 585         final int index = baseName.lastIndexOf(".js");
 586         if (index != -1) {
 587             baseName = baseName.substring(0, index);
 588         }
 589 
 590         baseName = baseName.replace('.', '_').replace('-', '_');
 591         if (! env._loader_per_compile) {
 592             baseName = baseName + installer.getUniqueScriptId();
 593         }
 594         final String mangled = NameCodec.encode(baseName);
 595 
 596         return mangled != null ? mangled : baseName;
 597     }
 598 
 599     private int nextCompileUnitIndex() {
 600         return compileUnits.size() + 1;
 601     }
 602 
 603     String firstCompileUnitName() {
 604         return SCRIPTS_PACKAGE + '/' + scriptName;
 605     }
 606 
 607     private String nextCompileUnitName() {
 608         return firstCompileUnitName() + '$' + nextCompileUnitIndex();
 609     }
 610 
 611     CompileUnit addCompileUnit(final long initialWeight) {
 612         return addCompileUnit(nextCompileUnitName(), initialWeight);
 613     }
 614 
 615     CompileUnit addCompileUnit(final String unitClassName) {
 616         return addCompileUnit(unitClassName, 0L);
 617     }
 618 
 619     private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) {
 620         final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight);
 621         compileUnits.add(compileUnit);
 622         LOG.fine("Added compile unit ", compileUnit);
 623         return compileUnit;
 624     }
 625 
 626     private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
 627         final ClassEmitter classEmitter = new ClassEmitter(env, sourceName, unitClassName, strict);
 628         final CompileUnit  compileUnit  = new CompileUnit(unitClassName, classEmitter, initialWeight);
 629 
 630         classEmitter.begin();
 631 
 632         final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE));
 633         initMethod.begin();
 634         initMethod.load(Type.OBJECT, 0);
 635         initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
 636         initMethod.returnVoid();
 637         initMethod.end();
 638 
 639         return compileUnit;
 640     }
 641 
 642     CompileUnit findUnit(final long weight) {
 643         for (final CompileUnit unit : compileUnits) {
 644             if (unit.canHold(weight)) {
 645                 unit.addWeight(weight);
 646                 return unit;
 647             }
 648         }
 649 
 650         return addCompileUnit(weight);
 651     }
 652 
 653     /**
 654      * Convert a package/class name to a binary name.
 655      *
 656      * @param name Package/class name.
 657      * @return Binary name.
 658      */
 659     public static String binaryName(final String name) {
 660         return name.replace('/', '.');
 661     }
 662 
 663     /**
 664      * Should we use integers for arithmetic operations as well?
 665      * TODO: We currently generate no overflow checks so this is
 666      * disabled
 667      *
 668      * @return true if arithmetic operations should not widen integer
 669      *   operands by default.
 670      */
 671     static boolean shouldUseIntegerArithmetic() {
 672         return USE_INT_ARITH;
 673     }
 674 
 675     private static final boolean USE_INT_ARITH;
 676 
 677     static {
 678         USE_INT_ARITH  =  Options.getBooleanProperty("nashorn.compiler.intarithmetic");
 679         assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
 680     }
 681 }