Fri, 03 May 2013 16:01:33 +0200
8013871: mem usage histograms enabled with compiler logging level set to more specific than or equals to info when --print-mem-usage flag is used
Reviewed-by: jlaskey, hannesw
1.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Fri May 03 15:33:54 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Fri May 03 16:01:33 2013 +0200 1.3 @@ -42,10 +42,13 @@ 1.4 import java.security.PrivilegedActionException; 1.5 import java.security.PrivilegedExceptionAction; 1.6 import java.util.Arrays; 1.7 +import java.util.Collections; 1.8 +import java.util.Comparator; 1.9 import java.util.EnumSet; 1.10 import java.util.HashMap; 1.11 import java.util.HashSet; 1.12 import java.util.LinkedList; 1.13 +import java.util.List; 1.14 import java.util.Map; 1.15 import java.util.Map.Entry; 1.16 import java.util.Set; 1.17 @@ -56,6 +59,8 @@ 1.18 import jdk.nashorn.internal.codegen.types.Type; 1.19 import jdk.nashorn.internal.ir.FunctionNode; 1.20 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 1.21 +import jdk.nashorn.internal.ir.debug.ClassHistogramElement; 1.22 +import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; 1.23 import jdk.nashorn.internal.runtime.CodeInstaller; 1.24 import jdk.nashorn.internal.runtime.DebugLogger; 1.25 import jdk.nashorn.internal.runtime.ScriptEnvironment; 1.26 @@ -289,6 +294,40 @@ 1.27 this(env, null, sequence(env._lazy_compilation), env._strict); 1.28 } 1.29 1.30 + private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) { 1.31 + final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification()); 1.32 + osc.calculateObjectSize(functionNode); 1.33 + 1.34 + final List<ClassHistogramElement> list = osc.getClassHistogram(); 1.35 + 1.36 + final StringBuilder sb = new StringBuilder(); 1.37 + final long totalSize = osc.calculateObjectSize(functionNode); 1.38 + sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB"); 1.39 + LOG.info(sb); 1.40 + 1.41 + Collections.sort(list, new Comparator<ClassHistogramElement>() { 1.42 + @Override 1.43 + public int compare(ClassHistogramElement o1, ClassHistogramElement o2) { 1.44 + final long diff = o1.getBytes() - o2.getBytes(); 1.45 + if (diff < 0) { 1.46 + return 1; 1.47 + } else if (diff > 0) { 1.48 + return -1; 1.49 + } else { 1.50 + return 0; 1.51 + } 1.52 + } 1.53 + }); 1.54 + for (final ClassHistogramElement e : list) { 1.55 + final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances()); 1.56 + LOG.info(line); 1.57 + if (e.getBytes() < totalSize / 20) { 1.58 + LOG.info(" ..."); 1.59 + break; // never mind, so little memory anyway 1.60 + } 1.61 + } 1.62 + } 1.63 + 1.64 /** 1.65 * Execute the compilation this Compiler was created with 1.66 * @param functionNode function node to compile from its current state 1.67 @@ -312,6 +351,10 @@ 1.68 for (final CompilationPhase phase : sequence) { 1.69 newFunctionNode = phase.apply(this, newFunctionNode); 1.70 1.71 + if (env._print_mem_usage) { 1.72 + printMemoryUsage(phase.toString(), newFunctionNode); 1.73 + } 1.74 + 1.75 final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L; 1.76 time += duration; 1.77
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java Fri May 03 16:01:33 2013 +0200 2.3 @@ -0,0 +1,113 @@ 2.4 +/* 2.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. Oracle designates this 2.11 + * particular file as subject to the "Classpath" exception as provided 2.12 + * by Oracle in the LICENSE file that accompanied this code. 2.13 + * 2.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.17 + * version 2 for more details (a copy is included in the LICENSE file that 2.18 + * accompanied this code). 2.19 + * 2.20 + * You should have received a copy of the GNU General Public License version 2.21 + * 2 along with this work; if not, write to the Free Software Foundation, 2.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.23 + * 2.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.25 + * or visit www.oracle.com if you need additional information or have any 2.26 + * questions. 2.27 + */ 2.28 + 2.29 +package jdk.nashorn.internal.ir.debug; 2.30 + 2.31 +import java.util.Comparator; 2.32 + 2.33 +/** 2.34 + * Class histogram element for IR / Java object instrumentation 2.35 + */ 2.36 +public class ClassHistogramElement { 2.37 + /** 2.38 + * Instance comparator 2.39 + */ 2.40 + public static final Comparator<ClassHistogramElement> COMPARE_INSTANCES = new Comparator<ClassHistogramElement>() { 2.41 + @Override 2.42 + public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { 2.43 + return (int)Math.abs(o1.instances - o2.instances); 2.44 + } 2.45 + }; 2.46 + 2.47 + /** 2.48 + * Bytes comparator 2.49 + */ 2.50 + public static final Comparator<ClassHistogramElement> COMPARE_BYTES = new Comparator<ClassHistogramElement>() { 2.51 + @Override 2.52 + public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { 2.53 + return (int)Math.abs(o1.bytes - o2.bytes); 2.54 + } 2.55 + }; 2.56 + 2.57 + /** 2.58 + * Classname comparator 2.59 + */ 2.60 + public static final Comparator<ClassHistogramElement> COMPARE_CLASSNAMES = new Comparator<ClassHistogramElement>() { 2.61 + @Override 2.62 + public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) { 2.63 + return o1.clazz.getCanonicalName().compareTo(o2.clazz.getCanonicalName()); 2.64 + } 2.65 + }; 2.66 + 2.67 + private final Class<?> clazz; 2.68 + private long instances; 2.69 + private long bytes; 2.70 + 2.71 + /** 2.72 + * Constructor 2.73 + * @param clazz class for which to construct histogram 2.74 + */ 2.75 + public ClassHistogramElement(final Class<?> clazz) { 2.76 + this.clazz = clazz; 2.77 + } 2.78 + 2.79 + /** 2.80 + * Add an instance 2.81 + * @param sizeInBytes byte count 2.82 + */ 2.83 + public void addInstance(final long sizeInBytes) { 2.84 + instances++; 2.85 + this.bytes += sizeInBytes; 2.86 + } 2.87 + 2.88 + /** 2.89 + * Get size in bytes 2.90 + * @return size in bytes 2.91 + */ 2.92 + public long getBytes() { 2.93 + return bytes; 2.94 + } 2.95 + 2.96 + /** 2.97 + * Get class 2.98 + * @return class 2.99 + */ 2.100 + public Class<?> getClazz() { 2.101 + return clazz; 2.102 + } 2.103 + 2.104 + /** 2.105 + * Get number of instances 2.106 + * @return number of instances 2.107 + */ 2.108 + public long getInstances() { 2.109 + return instances; 2.110 + } 2.111 + 2.112 + @Override 2.113 + public String toString() { 2.114 + return "ClassHistogramElement[class=" + clazz.getCanonicalName() + ", instances=" + instances + ", bytes=" + bytes + "]"; 2.115 + } 2.116 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java Fri May 03 16:01:33 2013 +0200 3.3 @@ -0,0 +1,457 @@ 3.4 +/* 3.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. Oracle designates this 3.11 + * particular file as subject to the "Classpath" exception as provided 3.12 + * by Oracle in the LICENSE file that accompanied this code. 3.13 + * 3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.17 + * version 2 for more details (a copy is included in the LICENSE file that 3.18 + * accompanied this code). 3.19 + * 3.20 + * You should have received a copy of the GNU General Public License version 3.21 + * 2 along with this work; if not, write to the Free Software Foundation, 3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.23 + * 3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.25 + * or visit www.oracle.com if you need additional information or have any 3.26 + * questions. 3.27 + */ 3.28 + 3.29 +package jdk.nashorn.internal.ir.debug; 3.30 + 3.31 +import java.lang.management.ManagementFactory; 3.32 +import java.lang.management.MemoryPoolMXBean; 3.33 +import java.lang.reflect.Array; 3.34 +import java.lang.reflect.Field; 3.35 +import java.lang.reflect.Modifier; 3.36 +import java.util.ArrayDeque; 3.37 +import java.util.ArrayList; 3.38 +import java.util.Arrays; 3.39 +import java.util.Deque; 3.40 +import java.util.IdentityHashMap; 3.41 +import java.util.LinkedList; 3.42 +import java.util.List; 3.43 +import java.util.Map; 3.44 + 3.45 +/** 3.46 + * Contains utility methods for calculating the memory usage of objects. It 3.47 + * only works on the HotSpot JVM, and infers the actual memory layout (32 bit 3.48 + * vs. 64 bit word size, compressed object pointers vs. uncompressed) from 3.49 + * best available indicators. It can reliably detect a 32 bit vs. 64 bit JVM. 3.50 + * It can only make an educated guess at whether compressed OOPs are used, 3.51 + * though; specifically, it knows what the JVM's default choice of OOP 3.52 + * compression would be based on HotSpot version and maximum heap sizes, but if 3.53 + * the choice is explicitly overridden with the <tt>-XX:{+|-}UseCompressedOops</tt> command line 3.54 + * switch, it can not detect 3.55 + * this fact and will report incorrect sizes, as it will presume the default JVM 3.56 + * behavior. 3.57 + * 3.58 + * @author Attila Szegedi 3.59 + */ 3.60 +public class ObjectSizeCalculator { 3.61 + 3.62 + /** 3.63 + * Describes constant memory overheads for various constructs in a JVM implementation. 3.64 + */ 3.65 + public interface MemoryLayoutSpecification { 3.66 + 3.67 + /** 3.68 + * Returns the fixed overhead of an array of any type or length in this JVM. 3.69 + * 3.70 + * @return the fixed overhead of an array. 3.71 + */ 3.72 + int getArrayHeaderSize(); 3.73 + 3.74 + /** 3.75 + * Returns the fixed overhead of for any {@link Object} subclass in this JVM. 3.76 + * 3.77 + * @return the fixed overhead of any object. 3.78 + */ 3.79 + int getObjectHeaderSize(); 3.80 + 3.81 + /** 3.82 + * Returns the quantum field size for a field owned by an object in this JVM. 3.83 + * 3.84 + * @return the quantum field size for an object. 3.85 + */ 3.86 + int getObjectPadding(); 3.87 + 3.88 + /** 3.89 + * Returns the fixed size of an object reference in this JVM. 3.90 + * 3.91 + * @return the size of all object references. 3.92 + */ 3.93 + int getReferenceSize(); 3.94 + 3.95 + /** 3.96 + * Returns the quantum field size for a field owned by one of an object's ancestor superclasses 3.97 + * in this JVM. 3.98 + * 3.99 + * @return the quantum field size for a superclass field. 3.100 + */ 3.101 + int getSuperclassFieldPadding(); 3.102 + } 3.103 + 3.104 + private static class CurrentLayout { 3.105 + private static final MemoryLayoutSpecification SPEC = 3.106 + getEffectiveMemoryLayoutSpecification(); 3.107 + } 3.108 + 3.109 + /** 3.110 + * Given an object, returns the total allocated size, in bytes, of the object 3.111 + * and all other objects reachable from it. Attempts to to detect the current JVM memory layout, 3.112 + * but may fail with {@link UnsupportedOperationException}; 3.113 + * 3.114 + * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do 3.115 + * anything special, it measures the size of all objects 3.116 + * reachable through it (which will include its class loader, and by 3.117 + * extension, all other Class objects loaded by 3.118 + * the same loader, and all the parent class loaders). It doesn't provide the 3.119 + * size of the static fields in the JVM class that the Class object 3.120 + * represents. 3.121 + * @return the total allocated size of the object and all other objects it 3.122 + * retains. 3.123 + * @throws UnsupportedOperationException if the current vm memory layout cannot be detected. 3.124 + */ 3.125 + public static long getObjectSize(final Object obj) throws UnsupportedOperationException { 3.126 + return obj == null ? 0 : new ObjectSizeCalculator(CurrentLayout.SPEC).calculateObjectSize(obj); 3.127 + } 3.128 + 3.129 + // Fixed object header size for arrays. 3.130 + private final int arrayHeaderSize; 3.131 + // Fixed object header size for non-array objects. 3.132 + private final int objectHeaderSize; 3.133 + // Padding for the object size - if the object size is not an exact multiple 3.134 + // of this, it is padded to the next multiple. 3.135 + private final int objectPadding; 3.136 + // Size of reference (pointer) fields. 3.137 + private final int referenceSize; 3.138 + // Padding for the fields of superclass before fields of subclasses are 3.139 + // added. 3.140 + private final int superclassFieldPadding; 3.141 + 3.142 + private final Map<Class<?>, ClassSizeInfo> classSizeInfos = new IdentityHashMap<>(); 3.143 + 3.144 + 3.145 + private final Map<Object, Object> alreadyVisited = new IdentityHashMap<>(); 3.146 + private final Map<Class<?>, ClassHistogramElement> histogram = new IdentityHashMap<>(); 3.147 + 3.148 + private final Deque<Object> pending = new ArrayDeque<>(16 * 1024); 3.149 + private long size; 3.150 + 3.151 + /** 3.152 + * Creates an object size calculator that can calculate object sizes for a given 3.153 + * {@code memoryLayoutSpecification}. 3.154 + * 3.155 + * @param memoryLayoutSpecification a description of the JVM memory layout. 3.156 + */ 3.157 + public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) { 3.158 + memoryLayoutSpecification.getClass(); 3.159 + arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize(); 3.160 + objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize(); 3.161 + objectPadding = memoryLayoutSpecification.getObjectPadding(); 3.162 + referenceSize = memoryLayoutSpecification.getReferenceSize(); 3.163 + superclassFieldPadding = memoryLayoutSpecification.getSuperclassFieldPadding(); 3.164 + } 3.165 + 3.166 + /** 3.167 + * Given an object, returns the total allocated size, in bytes, of the object 3.168 + * and all other objects reachable from it. 3.169 + * 3.170 + * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do 3.171 + * anything special, it measures the size of all objects 3.172 + * reachable through it (which will include its class loader, and by 3.173 + * extension, all other Class objects loaded by 3.174 + * the same loader, and all the parent class loaders). It doesn't provide the 3.175 + * size of the static fields in the JVM class that the Class object 3.176 + * represents. 3.177 + * @return the total allocated size of the object and all other objects it 3.178 + * retains. 3.179 + */ 3.180 + public synchronized long calculateObjectSize(final Object obj) { 3.181 + // Breadth-first traversal instead of naive depth-first with recursive 3.182 + // implementation, so we don't blow the stack traversing long linked lists. 3.183 + histogram.clear(); 3.184 + try { 3.185 + for (Object o = obj;;) { 3.186 + visit(o); 3.187 + if (pending.isEmpty()) { 3.188 + return size; 3.189 + } 3.190 + o = pending.removeFirst(); 3.191 + } 3.192 + } finally { 3.193 + alreadyVisited.clear(); 3.194 + pending.clear(); 3.195 + size = 0; 3.196 + } 3.197 + } 3.198 + 3.199 + /** 3.200 + * Get the class histograpm 3.201 + * @return class histogram element list 3.202 + */ 3.203 + public List<ClassHistogramElement> getClassHistogram() { 3.204 + return new ArrayList<>(histogram.values()); 3.205 + } 3.206 + 3.207 + private ClassSizeInfo getClassSizeInfo(final Class<?> clazz) { 3.208 + ClassSizeInfo csi = classSizeInfos.get(clazz); 3.209 + if(csi == null) { 3.210 + csi = new ClassSizeInfo(clazz); 3.211 + classSizeInfos.put(clazz, csi); 3.212 + } 3.213 + return csi; 3.214 + } 3.215 + 3.216 + private void visit(final Object obj) { 3.217 + if (alreadyVisited.containsKey(obj)) { 3.218 + return; 3.219 + } 3.220 + final Class<?> clazz = obj.getClass(); 3.221 + if (clazz == ArrayElementsVisitor.class) { 3.222 + ((ArrayElementsVisitor) obj).visit(this); 3.223 + } else { 3.224 + alreadyVisited.put(obj, obj); 3.225 + if (clazz.isArray()) { 3.226 + visitArray(obj); 3.227 + } else { 3.228 + getClassSizeInfo(clazz).visit(obj, this); 3.229 + } 3.230 + } 3.231 + } 3.232 + 3.233 + private void visitArray(final Object array) { 3.234 + final Class<?> arrayClass = array.getClass(); 3.235 + final Class<?> componentType = arrayClass.getComponentType(); 3.236 + final int length = Array.getLength(array); 3.237 + if (componentType.isPrimitive()) { 3.238 + increaseByArraySize(arrayClass, length, getPrimitiveFieldSize(componentType)); 3.239 + } else { 3.240 + increaseByArraySize(arrayClass, length, referenceSize); 3.241 + // If we didn't use an ArrayElementsVisitor, we would be enqueueing every 3.242 + // element of the array here instead. For large arrays, it would 3.243 + // tremendously enlarge the queue. In essence, we're compressing it into 3.244 + // a small command object instead. This is different than immediately 3.245 + // visiting the elements, as their visiting is scheduled for the end of 3.246 + // the current queue. 3.247 + switch (length) { 3.248 + case 0: { 3.249 + break; 3.250 + } 3.251 + case 1: { 3.252 + enqueue(Array.get(array, 0)); 3.253 + break; 3.254 + } 3.255 + default: { 3.256 + enqueue(new ArrayElementsVisitor((Object[]) array)); 3.257 + } 3.258 + } 3.259 + } 3.260 + } 3.261 + 3.262 + private void increaseByArraySize(final Class<?> clazz, final int length, final long elementSize) { 3.263 + increaseSize(clazz, roundTo(arrayHeaderSize + length * elementSize, objectPadding)); 3.264 + } 3.265 + 3.266 + private static class ArrayElementsVisitor { 3.267 + private final Object[] array; 3.268 + 3.269 + ArrayElementsVisitor(final Object[] array) { 3.270 + this.array = array; 3.271 + } 3.272 + 3.273 + public void visit(final ObjectSizeCalculator calc) { 3.274 + for (final Object elem : array) { 3.275 + if (elem != null) { 3.276 + calc.visit(elem); 3.277 + } 3.278 + } 3.279 + } 3.280 + } 3.281 + 3.282 + void enqueue(final Object obj) { 3.283 + if (obj != null) { 3.284 + pending.addLast(obj); 3.285 + } 3.286 + } 3.287 + 3.288 + void increaseSize(final Class<?> clazz, final long objectSize) { 3.289 + ClassHistogramElement he = histogram.get(clazz); 3.290 + if(he == null) { 3.291 + he = new ClassHistogramElement(clazz); 3.292 + histogram.put(clazz, he); 3.293 + } 3.294 + he.addInstance(objectSize); 3.295 + size += objectSize; 3.296 + } 3.297 + 3.298 + static long roundTo(final long x, final int multiple) { 3.299 + return ((x + multiple - 1) / multiple) * multiple; 3.300 + } 3.301 + 3.302 + private class ClassSizeInfo { 3.303 + // Padded fields + header size 3.304 + private final long objectSize; 3.305 + // Only the fields size - used to calculate the subclasses' memory 3.306 + // footprint. 3.307 + private final long fieldsSize; 3.308 + private final Field[] referenceFields; 3.309 + 3.310 + public ClassSizeInfo(final Class<?> clazz) { 3.311 + long newFieldsSize = 0; 3.312 + final List<Field> newReferenceFields = new LinkedList<>(); 3.313 + for (Field f : clazz.getDeclaredFields()) { 3.314 + if (Modifier.isStatic(f.getModifiers())) { 3.315 + continue; 3.316 + } 3.317 + final Class<?> type = f.getType(); 3.318 + if (type.isPrimitive()) { 3.319 + newFieldsSize += getPrimitiveFieldSize(type); 3.320 + } else { 3.321 + f.setAccessible(true); 3.322 + newReferenceFields.add(f); 3.323 + newFieldsSize += referenceSize; 3.324 + } 3.325 + } 3.326 + final Class<?> superClass = clazz.getSuperclass(); 3.327 + if (superClass != null) { 3.328 + final ClassSizeInfo superClassInfo = getClassSizeInfo(superClass); 3.329 + newFieldsSize += roundTo(superClassInfo.fieldsSize, superclassFieldPadding); 3.330 + newReferenceFields.addAll(Arrays.asList(superClassInfo.referenceFields)); 3.331 + } 3.332 + this.fieldsSize = newFieldsSize; 3.333 + this.objectSize = roundTo(objectHeaderSize + newFieldsSize, objectPadding); 3.334 + this.referenceFields = newReferenceFields.toArray( 3.335 + new Field[newReferenceFields.size()]); 3.336 + } 3.337 + 3.338 + void visit(final Object obj, final ObjectSizeCalculator calc) { 3.339 + calc.increaseSize(obj.getClass(), objectSize); 3.340 + enqueueReferencedObjects(obj, calc); 3.341 + } 3.342 + 3.343 + public void enqueueReferencedObjects(final Object obj, final ObjectSizeCalculator calc) { 3.344 + for (Field f : referenceFields) { 3.345 + try { 3.346 + calc.enqueue(f.get(obj)); 3.347 + } catch (IllegalAccessException e) { 3.348 + final AssertionError ae = new AssertionError( 3.349 + "Unexpected denial of access to " + f); 3.350 + ae.initCause(e); 3.351 + throw ae; 3.352 + } 3.353 + } 3.354 + } 3.355 + } 3.356 + 3.357 + private static long getPrimitiveFieldSize(final Class<?> type) { 3.358 + if (type == boolean.class || type == byte.class) { 3.359 + return 1; 3.360 + } 3.361 + if (type == char.class || type == short.class) { 3.362 + return 2; 3.363 + } 3.364 + if (type == int.class || type == float.class) { 3.365 + return 4; 3.366 + } 3.367 + if (type == long.class || type == double.class) { 3.368 + return 8; 3.369 + } 3.370 + throw new AssertionError("Encountered unexpected primitive type " + 3.371 + type.getName()); 3.372 + } 3.373 + 3.374 + /** 3.375 + * Return the current memory usage 3.376 + * @return current memory usage derived from system configuration 3.377 + */ 3.378 + public static MemoryLayoutSpecification getEffectiveMemoryLayoutSpecification() { 3.379 + final String vmName = System.getProperty("java.vm.name"); 3.380 + if (vmName == null || !vmName.startsWith("Java HotSpot(TM) ")) { 3.381 + throw new UnsupportedOperationException( 3.382 + "ObjectSizeCalculator only supported on HotSpot VM"); 3.383 + } 3.384 + 3.385 + final String dataModel = System.getProperty("sun.arch.data.model"); 3.386 + if ("32".equals(dataModel)) { 3.387 + // Running with 32-bit data model 3.388 + return new MemoryLayoutSpecification() { 3.389 + @Override public int getArrayHeaderSize() { 3.390 + return 12; 3.391 + } 3.392 + @Override public int getObjectHeaderSize() { 3.393 + return 8; 3.394 + } 3.395 + @Override public int getObjectPadding() { 3.396 + return 8; 3.397 + } 3.398 + @Override public int getReferenceSize() { 3.399 + return 4; 3.400 + } 3.401 + @Override public int getSuperclassFieldPadding() { 3.402 + return 4; 3.403 + } 3.404 + }; 3.405 + } else if (!"64".equals(dataModel)) { 3.406 + throw new UnsupportedOperationException("Unrecognized value '" + 3.407 + dataModel + "' of sun.arch.data.model system property"); 3.408 + } 3.409 + 3.410 + final String strVmVersion = System.getProperty("java.vm.version"); 3.411 + final int vmVersion = Integer.parseInt(strVmVersion.substring(0, 3.412 + strVmVersion.indexOf('.'))); 3.413 + if (vmVersion >= 17) { 3.414 + long maxMemory = 0; 3.415 + for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) { 3.416 + maxMemory += mp.getUsage().getMax(); 3.417 + } 3.418 + if (maxMemory < 30L * 1024 * 1024 * 1024) { 3.419 + // HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total 3.420 + // for all memory pools (yes, including code cache). 3.421 + return new MemoryLayoutSpecification() { 3.422 + @Override public int getArrayHeaderSize() { 3.423 + return 16; 3.424 + } 3.425 + @Override public int getObjectHeaderSize() { 3.426 + return 12; 3.427 + } 3.428 + @Override public int getObjectPadding() { 3.429 + return 8; 3.430 + } 3.431 + @Override public int getReferenceSize() { 3.432 + return 4; 3.433 + } 3.434 + @Override public int getSuperclassFieldPadding() { 3.435 + return 4; 3.436 + } 3.437 + }; 3.438 + } 3.439 + } 3.440 + 3.441 + // In other cases, it's a 64-bit uncompressed OOPs object model 3.442 + return new MemoryLayoutSpecification() { 3.443 + @Override public int getArrayHeaderSize() { 3.444 + return 24; 3.445 + } 3.446 + @Override public int getObjectHeaderSize() { 3.447 + return 16; 3.448 + } 3.449 + @Override public int getObjectPadding() { 3.450 + return 8; 3.451 + } 3.452 + @Override public int getReferenceSize() { 3.453 + return 8; 3.454 + } 3.455 + @Override public int getSuperclassFieldPadding() { 3.456 + return 8; 3.457 + } 3.458 + }; 3.459 + } 3.460 +}
4.1 --- a/src/jdk/nashorn/internal/objects/Global.java Fri May 03 15:33:54 2013 +0200 4.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Fri May 03 16:01:33 2013 +0200 4.3 @@ -1625,7 +1625,6 @@ 4.4 this.addOwnProperty("Debug", Attribute.NOT_ENUMERABLE, initConstructor("Debug")); 4.5 } 4.6 4.7 - @SuppressWarnings("resource") 4.8 private static Object printImpl(final boolean newLine, final Object... objects) { 4.9 final PrintWriter out = Global.getEnv().getOut(); 4.10
5.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Fri May 03 15:33:54 2013 +0200 5.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Fri May 03 16:01:33 2013 +0200 5.3 @@ -171,7 +171,6 @@ 5.4 * @param str text to write 5.5 * @param crlf write a carriage return/new line after text 5.6 */ 5.7 - @SuppressWarnings("resource") 5.8 public static void err(final String str, final boolean crlf) { 5.9 final PrintWriter err = Context.getCurrentErr(); 5.10 if (err != null) {
6.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri May 03 15:33:54 2013 +0200 6.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri May 03 16:01:33 2013 +0200 6.3 @@ -140,6 +140,9 @@ 6.4 /** Print resulting bytecode for script */ 6.5 public final boolean _print_code; 6.6 6.7 + /** Print memory usage for IR after each phase */ 6.8 + public final boolean _print_mem_usage; 6.9 + 6.10 /** Print function will no print newline characters */ 6.11 public final boolean _print_no_newline; 6.12 6.13 @@ -211,6 +214,7 @@ 6.14 _print_ast = options.getBoolean("print.ast"); 6.15 _print_lower_ast = options.getBoolean("print.lower.ast"); 6.16 _print_code = options.getBoolean("print.code"); 6.17 + _print_mem_usage = options.getBoolean("print.mem.usage"); 6.18 _print_no_newline = options.getBoolean("print.no.newline"); 6.19 _print_parse = options.getBoolean("print.parse"); 6.20 _print_lower_parse = options.getBoolean("print.lower.parse");
7.1 --- a/src/jdk/nashorn/internal/runtime/options/Options.java Fri May 03 15:33:54 2013 +0200 7.2 +++ b/src/jdk/nashorn/internal/runtime/options/Options.java Fri May 03 16:01:33 2013 +0200 7.3 @@ -243,7 +243,7 @@ 7.4 */ 7.5 public String getString(final String key) { 7.6 final Option<?> option = get(key); 7.7 - if(option != null) { 7.8 + if (option != null) { 7.9 final String value = (String)option.getValue(); 7.10 if(value != null) { 7.11 return value.intern();
8.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri May 03 15:33:54 2013 +0200 8.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri May 03 16:01:33 2013 +0200 8.3 @@ -247,6 +247,12 @@ 8.4 desc="Print bytecode." \ 8.5 } 8.6 8.7 +nashorn.option.print.mem.usage = { \ 8.8 + name="--print-mem-usage", \ 8.9 + is_undocumented=true, \ 8.10 + desc="Print memory usage of IR after each compile stage." \ 8.11 +} 8.12 + 8.13 nashorn.option.print.no.newline = { \ 8.14 name="--print-no-newline", \ 8.15 is_undocumented=true, \
9.1 --- a/src/jdk/nashorn/tools/Shell.java Fri May 03 15:33:54 2013 +0200 9.2 +++ b/src/jdk/nashorn/tools/Shell.java Fri May 03 16:01:33 2013 +0200 9.3 @@ -173,9 +173,9 @@ 9.4 9.5 if (env._fx) { 9.6 return runFXScripts(context, global, files); 9.7 - } else { 9.8 - return runScripts(context, global, files); 9.9 } 9.10 + 9.11 + return runScripts(context, global, files); 9.12 } 9.13 9.14 /**