From aleksey.shipilev at oracle.com Wed Jan 13 14:09:14 2016 From: aleksey.shipilev at oracle.com (aleksey.shipilev at oracle.com) Date: Wed, 13 Jan 2016 14:09:14 +0000 Subject: hg: code-tools/jol: Add long[0] example to JOLSample_25_ArrayAlignment. Message-ID: <201601131409.u0DE9E2u015190@aojmv0008.oracle.com> Changeset: 4443d2696dcf Author: shade Date: 2016-01-13 17:09 +0300 URL: http://hg.openjdk.java.net/code-tools/jol/rev/4443d2696dcf Add long[0] example to JOLSample_25_ArrayAlignment. ! jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_25_ArrayAlignment.java From timur.gbd at gmail.com Wed Jan 20 23:44:50 2016 From: timur.gbd at gmail.com (Timur Gibadullin) Date: Thu, 21 Jan 2016 02:44:50 +0300 Subject: [PATCH] 7901019: jol estimates do not take AllocationStyle into the account Message-ID: Hi! Thanks for the jol, which is such a handy tool. I'd like to improve it and propose patch. I am trying to solve a bug with hotspot layouter, which is described in the issue in the bug database. And this is my first attempt to solve it, I prepared a patch (sending as attahced to this mail). In the patch I followed Aleksey's comment from the issue and added fieldAllocationStyle option to the HotspotLayouter and changed HotspotLayouter's layout, now it emulates layout_fields method of the ClassFileParser from Hotspot, actually, I ported this method from the Hotspot, refactored it and dropped some unnecessary for the jol parts. Also I made little additions to FieldData and ClassData classes, they are required by the new layout method, and added a new example, which is called JOLSample_26_Hotspot. Please, share your thoughts and give me any feedback and comments about my patch. -- Best regards, Timur Gibadullin From timur.gbd at gmail.com Thu Jan 21 00:01:45 2016 From: timur.gbd at gmail.com (Timur Gibadullin) Date: Thu, 21 Jan 2016 03:01:45 +0300 Subject: [PATCH] 7901019: jol estimates do not take AllocationStyle into the account In-Reply-To: References: Message-ID: Sorry, forgot to attach the patch. 2016-01-21 2:44 GMT+03:00 Timur Gibadullin : > Hi! Thanks for the jol, which is such a handy tool. I'd like to improve it > and propose patch. I am trying to solve a bug with hotspot layouter, which > is described in the issue > in the bug > database. And this is my first attempt to solve it, I prepared a patch (sending > as attahced to this mail). In the patch I followed Aleksey's comment from > the issue and added fieldAllocationStyle option to the HotspotLayouter and changed > HotspotLayouter's layout, now it emulates layout_fields method of the ClassFileParser > from Hotspot, actually, I ported this method from the Hotspot, refactored > it and dropped some unnecessary for the jol parts. Also I made little > additions to FieldData and ClassData classes, they are required by the new layout > method, and added a new example, which is called JOLSample_26_Hotspot. > Please, share your thoughts and give me any feedback and comments about my > patch. > > > -- > Best regards, Timur Gibadullin > -- Best regards, Timur Gibadullin From aleksey.shipilev at oracle.com Fri Jan 22 10:21:15 2016 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 22 Jan 2016 13:21:15 +0300 Subject: [PATCH] 7901019: jol estimates do not take AllocationStyle into the account In-Reply-To: References: Message-ID: <56A2029B.5080909@oracle.com> Hi Timur, The list is stripping the unknown attachments. The attachment should be one of the following MIME types: text/plain text/x-diff text/x-patch You can re-send directly to me if you want to know what's the MIME type for your current attachment. Cheers, -Aleksey On 01/21/2016 03:01 AM, Timur Gibadullin wrote: > Sorry, forgot to attach the patch. > > 2016-01-21 2:44 GMT+03:00 Timur Gibadullin : > >> Hi! Thanks for the jol, which is such a handy tool. I'd like to improve it >> and propose patch. I am trying to solve a bug with hotspot layouter, which >> is described in the issue >> in the bug >> database. And this is my first attempt to solve it, I prepared a patch (sending >> as attahced to this mail). In the patch I followed Aleksey's comment from >> the issue and added fieldAllocationStyle option to the HotspotLayouter and changed >> HotspotLayouter's layout, now it emulates layout_fields method of the ClassFileParser >> from Hotspot, actually, I ported this method from the Hotspot, refactored >> it and dropped some unnecessary for the jol parts. Also I made little >> additions to FieldData and ClassData classes, they are required by the new layout >> method, and added a new example, which is called JOLSample_26_Hotspot. >> Please, share your thoughts and give me any feedback and comments about my >> patch. >> >> >> -- >> Best regards, Timur Gibadullin >> > > > From timur.gbd at gmail.com Mon Jan 25 09:24:41 2016 From: timur.gbd at gmail.com (=?utf-8?B?0KLQuNC80YPRgCDQk9C40LHQsNC00YPQu9C70LjQvQ==?=) Date: Mon, 25 Jan 2016 12:24:41 +0300 Subject: [PATCH] 7901019: jol estimates do not take AllocationStyle into the account In-Reply-To: <56A2029B.5080909@oracle.com> References: <56A2029B.5080909@oracle.com> Message-ID: Ok, re-sent patch via apple?s mail client. -------------- next part -------------- > 22 ???. 2016 ?., ? 13:21, Aleksey Shipilev ???????(?): > > Hi Timur, > > The list is stripping the unknown attachments. The attachment should be > one of the following MIME types: > text/plain > text/x-diff > text/x-patch > > You can re-send directly to me if you want to know what's the MIME type > for your current attachment. > > Cheers, > -Aleksey > > On 01/21/2016 03:01 AM, Timur Gibadullin wrote: >> Sorry, forgot to attach the patch. >> >> 2016-01-21 2:44 GMT+03:00 Timur Gibadullin : >> >>> Hi! Thanks for the jol, which is such a handy tool. I'd like to improve it >>> and propose patch. I am trying to solve a bug with hotspot layouter, which >>> is described in the issue >>> in the bug >>> database. And this is my first attempt to solve it, I prepared a patch (sending >>> as attahced to this mail). In the patch I followed Aleksey's comment from >>> the issue and added fieldAllocationStyle option to the HotspotLayouter and changed >>> HotspotLayouter's layout, now it emulates layout_fields method of the ClassFileParser >>> from Hotspot, actually, I ported this method from the Hotspot, refactored >>> it and dropped some unnecessary for the jol parts. Also I made little >>> additions to FieldData and ClassData classes, they are required by the new layout >>> method, and added a new example, which is called JOLSample_26_Hotspot. >>> Please, share your thoughts and give me any feedback and comments about my >>> patch. >>> >>> >>> -- >>> Best regards, Timur Gibadullin >>> >> >> >> > > From aleksey.shipilev at oracle.com Mon Jan 25 16:57:20 2016 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Mon, 25 Jan 2016 19:57:20 +0300 Subject: [PATCH] 7901019: jol estimates do not take AllocationStyle into the account In-Reply-To: References: <56A2029B.5080909@oracle.com> Message-ID: <56A653F0.4060708@oracle.com> Nope, the attachment is still striped. -Aleksey On 01/25/2016 12:24 PM, ????? ?????????? wrote: > Ok, re-sent patch via apple?s mail client. > > > > >> 22 ???. 2016 ?., ? 13:21, Aleksey Shipilev ???????(?): >> >> Hi Timur, >> >> The list is stripping the unknown attachments. The attachment should be >> one of the following MIME types: >> text/plain >> text/x-diff >> text/x-patch >> >> You can re-send directly to me if you want to know what's the MIME type >> for your current attachment. >> >> Cheers, >> -Aleksey >> >> On 01/21/2016 03:01 AM, Timur Gibadullin wrote: >>> Sorry, forgot to attach the patch. >>> >>> 2016-01-21 2:44 GMT+03:00 Timur Gibadullin : >>> >>>> Hi! Thanks for the jol, which is such a handy tool. I'd like to improve it >>>> and propose patch. I am trying to solve a bug with hotspot layouter, which >>>> is described in the issue >>>> in the bug >>>> database. And this is my first attempt to solve it, I prepared a patch (sending >>>> as attahced to this mail). In the patch I followed Aleksey's comment from >>>> the issue and added fieldAllocationStyle option to the HotspotLayouter and changed >>>> HotspotLayouter's layout, now it emulates layout_fields method of the ClassFileParser >>>> from Hotspot, actually, I ported this method from the Hotspot, refactored >>>> it and dropped some unnecessary for the jol parts. Also I made little >>>> additions to FieldData and ClassData classes, they are required by the new layout >>>> method, and added a new example, which is called JOLSample_26_Hotspot. >>>> Please, share your thoughts and give me any feedback and comments about my >>>> patch. >>>> >>>> >>>> -- >>>> Best regards, Timur Gibadullin >>>> >>> >>> >>> >> >> > From timur.gbd at gmail.com Mon Jan 25 23:40:08 2016 From: timur.gbd at gmail.com (=?UTF-8?B?0KLQuNC80YPRgCDQk9C40LHQsNC00YPQu9C70LjQvQ==?=) Date: Tue, 26 Jan 2016 02:40:08 +0300 Subject: [PATCH] 7901019: jol estimates do not take AllocationStyle into the account In-Reply-To: <56A653F0.4060708@oracle.com> References: <56A2029B.5080909@oracle.com> <56A653F0.4060708@oracle.com> Message-ID: <56A6B258.1080807@gmail.com> Sent via thunderbird, seems it is now text/plain. On 25.01.16 19:57, Aleksey Shipilev wrote: > Nope, the attachment is still striped. > > -Aleksey > > On 01/25/2016 12:24 PM, ????? ?????????? wrote: >> Ok, re-sent patch via apple?s mail client. >> >> >> >> >>> 22 ???. 2016 ?., ? 13:21, Aleksey Shipilev ???????(?): >>> >>> Hi Timur, >>> >>> The list is stripping the unknown attachments. The attachment should be >>> one of the following MIME types: >>> text/plain >>> text/x-diff >>> text/x-patch >>> >>> You can re-send directly to me if you want to know what's the MIME type >>> for your current attachment. >>> >>> Cheers, >>> -Aleksey >>> >>> On 01/21/2016 03:01 AM, Timur Gibadullin wrote: >>>> Sorry, forgot to attach the patch. >>>> >>>> 2016-01-21 2:44 GMT+03:00 Timur Gibadullin : >>>> >>>>> Hi! Thanks for the jol, which is such a handy tool. I'd like to improve it >>>>> and propose patch. I am trying to solve a bug with hotspot layouter, which >>>>> is described in the issue >>>>> in the bug >>>>> database. And this is my first attempt to solve it, I prepared a patch (sending >>>>> as attahced to this mail). In the patch I followed Aleksey's comment from >>>>> the issue and added fieldAllocationStyle option to the HotspotLayouter and changed >>>>> HotspotLayouter's layout, now it emulates layout_fields method of the ClassFileParser >>>>> from Hotspot, actually, I ported this method from the Hotspot, refactored >>>>> it and dropped some unnecessary for the jol parts. Also I made little >>>>> additions to FieldData and ClassData classes, they are required by the new layout >>>>> method, and added a new example, which is called JOLSample_26_Hotspot. >>>>> Please, share your thoughts and give me any feedback and comments about my >>>>> patch. >>>>> >>>>> >>>>> -- >>>>> Best regards, Timur Gibadullin >>>>> >>>> >>>> >>> > -------------- next part -------------- # HG changeset patch # User Timur Gibadullin # Date 1453332792 -10800 # Thu Jan 21 02:33:12 2016 +0300 # Node ID 72b69400980fe84c159e35f3ff053c68d6925297 # Parent 4443d2696dcf87184e805dd475774cffee8c3cc1 7901019: jol estimates do not take AllocationStyle into the account diff -r 4443d2696dcf -r 72b69400980f jol-core/src/main/java/org/openjdk/jol/info/ClassData.java --- a/jol-core/src/main/java/org/openjdk/jol/info/ClassData.java Wed Jan 13 17:09:03 2016 +0300 +++ b/jol-core/src/main/java/org/openjdk/jol/info/ClassData.java Thu Jan 21 02:33:12 2016 +0300 @@ -24,13 +24,17 @@ */ package org.openjdk.jol.info; +import org.openjdk.jol.datamodel.DataModel; + import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.EnumMap; import java.util.List; +import sun.misc.Contended; /** * Holds the class data, without the layout information. @@ -92,6 +96,13 @@ } ClassData cd = new ClassData(o, klass.getCanonicalName()); + Class superKlass = klass.getSuperclass(); + + cd.isContended = klass.getAnnotation(Contended.class) != null; + + if (superKlass != null) { + cd.addSuperClassData(klass.getSuperclass()); + } do { for (Field f : klass.getDeclaredFields()) { @@ -113,6 +124,8 @@ private final String arrayComponentKlass; private final int length; private final boolean isArray; + private boolean isContended; + private ClassData superClass; /** * Constructs the empty ClassData, suited for regular class. @@ -130,6 +143,8 @@ this.arrayKlass = null; this.arrayComponentKlass = null; this.isArray = false; + this.superClass = null; + this.isContended = false; } /** @@ -152,6 +167,8 @@ this.classNames = null; this.length = length; this.isArray = true; + this.superClass = null; + this.isContended = false; } /** @@ -164,6 +181,15 @@ } /** + * Add the super-class data of the class. + * + * @param superClass super class + */ + public void addSuperClassData(Class superClass) { + this.superClass = parseClass(superClass); + } + + /** * Add the field data. * * @param fieldData the data to add @@ -183,6 +209,21 @@ } /** + * Counts the total size of fields. + * + * @return fields size + */ + public int fieldSize(DataModel model) { + int fieldSize = 0; + + for (FieldData f : fields) { + fieldSize += model.sizeOf(f.typeClass()); + } + + return fieldSize; + } + + /** * Get the fields' data for the given class. * * @param klass class name @@ -227,6 +268,24 @@ } /** + * Get ClassData of the super-class. + * + * @return ClassData + */ + public ClassData superClass() { + return superClass; + } + + /** + * Does the class have @Contended annotation? + * + * @return true, if class has @Contended annotation; false otherwise + */ + public boolean isContended() { + return isContended; + } + + /** * Answer the array class for this class data. * * @return array class name, e.g. "int[]". diff -r 4443d2696dcf -r 72b69400980f jol-core/src/main/java/org/openjdk/jol/info/FieldData.java --- a/jol-core/src/main/java/org/openjdk/jol/info/FieldData.java Wed Jan 13 17:09:03 2016 +0300 +++ b/jol-core/src/main/java/org/openjdk/jol/info/FieldData.java Thu Jan 21 02:33:12 2016 +0300 @@ -28,6 +28,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import sun.misc.Contended; /** * Holds the field information, without the layout. @@ -45,7 +46,7 @@ * @return field data */ public static FieldData create(String hostKlass, String fieldName, String fieldType) { - return new FieldData(null, -1, hostKlass, fieldName, fieldType); + return new FieldData(null, -1, hostKlass, fieldName, fieldType, false, null); } /** @@ -55,7 +56,17 @@ * @return field data */ public static FieldData parse(Field field) { - return new FieldData(field, computeOffset(field), field.getDeclaringClass().getSimpleName(), field.getName(), field.getType().getSimpleName()); + Contended contentded = field.getAnnotation(Contended.class); + boolean isContended = contentded != null; + return new FieldData( + field, + computeOffset(field), + field.getDeclaringClass().getSimpleName(), + field.getName(), + field.getType().getSimpleName(), + isContended, + isContended ? contentded.value() : null + ); } private final String name; @@ -63,13 +74,17 @@ private final String klass; private final Field refField; private final int vmOffset; + private final boolean isContended; + private final String contendedGroup; - private FieldData(Field refField, int vmOffset, String hostKlass, String fieldName, String fieldType) { + private FieldData(Field refField, int vmOffset, String hostKlass, String fieldName, String fieldType, boolean isContended, String contendedGroup) { this.klass = hostKlass; this.name = fieldName; this.type = fieldType; this.refField = refField; this.vmOffset = vmOffset; + this.isContended = isContended; + this.contendedGroup = contendedGroup; } private static int computeOffset(Field field) { @@ -108,6 +123,33 @@ } /** + * Answers whether the field has contentded annotation. + * + * @return true, if the field is contended + */ + public boolean isContended() { + return isContended; + } + + /** + * Get contentded group of the field. + * + * @return String + */ + public String contendedGroup() { + return contendedGroup; + } + + /** + * Get original Field. + * + * @return Field which is represented by the FieldData + */ + public Field refField() { + return refField; + } + + /** * Gets the string representation of field value, * if appropriate. * @@ -147,4 +189,7 @@ } } + public String toString() { + return refField.toString(); + } } diff -r 4443d2696dcf -r 72b69400980f jol-core/src/main/java/org/openjdk/jol/layouters/HotSpotLayouter.java --- a/jol-core/src/main/java/org/openjdk/jol/layouters/HotSpotLayouter.java Wed Jan 13 17:09:03 2016 +0300 +++ b/jol-core/src/main/java/org/openjdk/jol/layouters/HotSpotLayouter.java Thu Jan 21 02:33:12 2016 +0300 @@ -31,32 +31,91 @@ import org.openjdk.jol.info.FieldLayout; import org.openjdk.jol.util.MathUtil; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.IllegalStateException; +import java.util.Arrays; import java.util.BitSet; import java.util.Collection; +import java.util.EnumMap; +import java.util.HashSet; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; + /** * VM layout simulator. * * @author Aleksey Shipilev */ public class HotSpotLayouter implements Layouter { + // The next classes have predefined hard-coded fields offsets. + private static HashSet predefinedFieldsOffsetsClasses = new HashSet(Arrays.asList( + "java.lang.AssertionStatusDirectives", + "java.lang.Class", + "java.lang.ClassLoader", + "java.lang.ref.Reference", + "java.lang.ref.SoftReference", + "java.lang.StackTraceElement", + "java.lang.String", + "java.lang.Throwable", + "java.lang.Boolean", + "java.lang.Character", + "java.lang.Float", + "java.lang.Double", + "java.lang.Byte", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long" + )); + static final int CONTENDED_PADDING_WIDTH = Integer.getInteger("contendedPaddingWidth", 128); + private final DataModel model; private final boolean takeHierarchyGaps; private final boolean takeSuperGaps; private final boolean autoAlign; + private final boolean compactFields; + private final int fieldAllocationStyle; public HotSpotLayouter(DataModel model) { - this(model, false, false, false); + this(model, false, false, false, true, -1); } - public HotSpotLayouter(DataModel model, boolean takeHierarchyGaps, boolean takeSuperGaps, boolean autoAlign) { + public HotSpotLayouter(DataModel model, boolean takeHierarchyGaps, boolean takeSuperGaps, boolean autoAlign, boolean compactFields, int fieldAllocationStyle) { this.model = model; this.takeHierarchyGaps = takeHierarchyGaps; this.takeSuperGaps = takeSuperGaps; this.autoAlign = autoAlign; + this.compactFields = compactFields; + this.fieldAllocationStyle = fieldAllocationStyle; + } + + private enum FieldAllocationType { + OOP, // Oops + BYTE, // Boolean, Byte, char + SHORT, // shorts + WORD, // ints + DOUBLE, // aligned long or double + BAD_ALLOCATION_TYPE + } + + private FieldAllocationType allocationTypeFor(Field field) { + String simpleName = field.getType().getSimpleName(); + + if (simpleName.equals("oop") || simpleName.endsWith("[]")) { + return FieldAllocationType.OOP; + } else if (simpleName.equals("bool") || simpleName.equals("byte") || simpleName.equals("char")) { + return FieldAllocationType.BYTE; + } else if (simpleName.equals("short")) { + return FieldAllocationType.SHORT; + } else if (simpleName.equals("int")) { + return FieldAllocationType.WORD; + } else if (simpleName.equals("long") || simpleName.equals("double")) { + return FieldAllocationType.DOUBLE; + } + + return FieldAllocationType.BAD_ALLOCATION_TYPE; } @Override @@ -77,55 +136,321 @@ return new ClassLayout(cd, result, model.arrayHeaderSize(), instanceSize, false); } + EnumMap fieldsAllocationCount = new EnumMap(FieldAllocationType.class); + EnumMap nextOffset = new EnumMap(FieldAllocationType.class); + EnumMap spaceCount = new EnumMap(FieldAllocationType.class); + EnumMap spaceOffset = new EnumMap(FieldAllocationType.class); + EnumMap allocationTypeSizes = new EnumMap(FieldAllocationType.class); + + for (FieldAllocationType atype : FieldAllocationType.values()) { + fieldsAllocationCount.put(atype, 0); + nextOffset.put(atype, 0); + spaceCount.put(atype, 0); + spaceOffset.put(atype, 0); + } + allocationTypeSizes.put(FieldAllocationType.OOP, model.sizeOf("oop")); + allocationTypeSizes.put(FieldAllocationType.BYTE, model.sizeOf("byte")); + allocationTypeSizes.put(FieldAllocationType.SHORT, model.sizeOf("short")); + allocationTypeSizes.put(FieldAllocationType.WORD, model.sizeOf("int")); + allocationTypeSizes.put(FieldAllocationType.DOUBLE, model.sizeOf("long")); + List hierarchy = cd.classHierarchy(); + for (String k : hierarchy) { - BitSet claimed = new BitSet(); + Collection fields = cd.fieldsFor(k); + for (FieldData f : fields) { + FieldAllocationType atype = allocationTypeFor(f.refField()); + Integer count = (Integer) fieldsAllocationCount.get(atype); + fieldsAllocationCount.put(atype, ++count); + } + } - claimed.set(0, model.headerSize()); + int fieldSize = cd.superClass() == null ? 0 : cd.superClass().fieldSize(model); + int firstOopOffset = 0; + int nextFieldOffset = 0; + int nextPaddedOffset = 0; + + // Count the contended fields by type. + int contendedCount = 0; + EnumMap facContended = new EnumMap(FieldAllocationType.class); for (String k : hierarchy) { Collection fields = cd.fieldsFor(k); + for (FieldData f : fields) { + FieldAllocationType atype = allocationTypeFor(f.refField()); + if (f.isContended()) { + Integer count = facContended.get(atype); - SortedSet current = new TreeSet(); - for (int size : new int[]{8, 4, 2, 1}) { + facContended.put(atype, count == null ? 1 : ++count); + contendedCount++; + } + } + } + + int fieldsStart = model.headerSize() + fieldSize * model.sizeOf("oop"); + + nextFieldOffset = fieldsStart; + + boolean isContendedClass = cd.isContended(); + + // Class is contended, pad before all the fields + if (isContendedClass) { + nextFieldOffset += CONTENDED_PADDING_WIDTH; + } + + // Compute the non-contended fields count. + // The packing code below relies on these counts to determine if some field + // can be squeezed into the alignment gap. Contended fields are obviously + // exempt from that. + int doubleCount = fieldsAllocationCount.get(FieldAllocationType.DOUBLE) - + (facContended.containsKey(FieldAllocationType.DOUBLE) ? facContended.get(FieldAllocationType.DOUBLE) : 0); + int wordCount = fieldsAllocationCount.get(FieldAllocationType.WORD) - + (facContended.containsKey(FieldAllocationType.WORD) ? facContended.get(FieldAllocationType.WORD) : 0); + int shortCount = fieldsAllocationCount.get(FieldAllocationType.SHORT) - + (facContended.containsKey(FieldAllocationType.SHORT) ? facContended.get(FieldAllocationType.SHORT) : 0); + int byteCount = fieldsAllocationCount.get(FieldAllocationType.BYTE) - + (facContended.containsKey(FieldAllocationType.BYTE) ? facContended.get(FieldAllocationType.BYTE) : 0); + int oopCount = fieldsAllocationCount.get(FieldAllocationType.OOP) - + (facContended.containsKey(FieldAllocationType.OOP) ? facContended.get(FieldAllocationType.OOP) : 0); + + firstOopOffset = 0; // will be set for first oop field + + boolean compactFields = this.compactFields; + int allocationStyle = this.fieldAllocationStyle; + if (allocationStyle < 0 || allocationStyle > 2) { + allocationStyle = 1; // Optimistic + } + + // Use default fields allocation order for classes, which have predefined hard-coded fields offsets. + if ((allocationStyle != 0 || compactFields) && + predefinedFieldsOffsetsClasses.contains(cd.name())) { + allocationStyle = 0; // Allocate oops first + compactFields = false; // Don't compact fields + } + + // Rearrange fields for a given allocation style + if (allocationStyle == 0) { + // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields + nextOffset.put(FieldAllocationType.OOP, nextFieldOffset); + nextOffset.put(FieldAllocationType.DOUBLE, + nextOffset.get(FieldAllocationType.OOP) + (oopCount * model.sizeOf("oop"))); + } else if (allocationStyle == 1) { + // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields + nextOffset.put(FieldAllocationType.DOUBLE, nextFieldOffset); + } else if (allocationStyle == 2) { + // Fields allocation: oops fields in super and sub classes are together. + if (allocationStyle == 2) { + allocationStyle = 1; // allocate oops last + nextOffset.put(FieldAllocationType.DOUBLE, nextFieldOffset); + } + } else { + throw new IllegalStateException(); + } + + // Try to squeeze some of the fields into the gaps due to + // long/double alignment. + if (doubleCount > 0) { + int offset = nextOffset.get(FieldAllocationType.DOUBLE); + nextOffset.put(FieldAllocationType.DOUBLE, MathUtil.align(offset, model.sizeOf("long"))); + if (compactFields && offset != nextOffset.get(FieldAllocationType.DOUBLE)) { + // Allocate available fields into the gap before double field. + int length = nextOffset.get(FieldAllocationType.DOUBLE) - offset; + spaceOffset.put(FieldAllocationType.WORD, offset); + if (wordCount > 0) { + wordCount -= 1; + spaceCount.put(FieldAllocationType.WORD, 1); // Only one will fit + length -= allocationTypeSizes.get(FieldAllocationType.WORD); + offset += allocationTypeSizes.get(FieldAllocationType.WORD); + } + spaceOffset.put(FieldAllocationType.SHORT, offset); + while (length >= allocationTypeSizes.get(FieldAllocationType.SHORT) && shortCount > 0) { + shortCount -= 1; + spaceCount.put(FieldAllocationType.SHORT, spaceCount.get(FieldAllocationType.SHORT) + 1); + length -= allocationTypeSizes.get(FieldAllocationType.SHORT); + offset += allocationTypeSizes.get(FieldAllocationType.SHORT); + } + spaceOffset.put(FieldAllocationType.BYTE, offset); + while (length > 0 && byteCount > 0) { + byteCount -= 1; + spaceCount.put(FieldAllocationType.BYTE, spaceCount.get(FieldAllocationType.BYTE) + 1); + length -= 1; + } + // Allocate oop field in the gap if there are no other fields for that. + spaceOffset.put(FieldAllocationType.OOP, offset); + if (length >= allocationTypeSizes.get(FieldAllocationType.OOP) && oopCount > 0 && + allocationStyle != 0) { // when oop fields not first + oopCount -= 1; + spaceCount.put(FieldAllocationType.OOP, 1); // Only one will fit + length -= allocationTypeSizes.get(FieldAllocationType.OOP); + offset += allocationTypeSizes.get(FieldAllocationType.OOP); + } + } + } + + nextOffset.put(FieldAllocationType.WORD, nextOffset.get(FieldAllocationType.DOUBLE) + + (doubleCount * allocationTypeSizes.get(FieldAllocationType.DOUBLE))); + nextOffset.put(FieldAllocationType.SHORT, nextOffset.get(FieldAllocationType.WORD) + + (wordCount * allocationTypeSizes.get(FieldAllocationType.WORD))); + nextOffset.put(FieldAllocationType.BYTE, nextOffset.get(FieldAllocationType.SHORT) + + (shortCount * allocationTypeSizes.get(FieldAllocationType.SHORT))); + nextPaddedOffset = nextOffset.get(FieldAllocationType.BYTE) + byteCount; + + // let oops jump before padding with this allocation style + if (allocationStyle == 1) { + nextOffset.put(FieldAllocationType.OOP, nextPaddedOffset); + if (oopCount > 0) { + nextOffset.put(FieldAllocationType.OOP, MathUtil.align(nextOffset.get(FieldAllocationType.OOP), allocationTypeSizes.get(FieldAllocationType.OOP))); + } + nextPaddedOffset = nextOffset.get(FieldAllocationType.OOP) + (oopCount * allocationTypeSizes.get(FieldAllocationType.OOP)); + } + + HashSet layoutedFields = new HashSet(); + + // Iterate over fields again and compute correct offsets. + // The field allocation type was temporarily stored in the offset slot. + // oop fields are located before non-oop fields. + for (String k : hierarchy) { + + Collection fields = cd.fieldsFor(k); + + for (FieldData f : fields) { + + // skip already laid out fields + if (layoutedFields.contains(f.toString())) continue; + + // contended instance fields are handled below + if (f.isContended()) continue; + + int realOffset = 0; + FieldAllocationType atype = allocationTypeFor(f.refField()); + int allocationTypeSize = allocationTypeSizes.get(atype); + int allocationTypeSpaceCount = spaceCount.get(atype); + int allocationTypeSpaceOffset = spaceOffset.get(atype); + + // pack the rest of the fields + if (atype == FieldAllocationType.DOUBLE) { + int nextDoubleOffset = nextOffset.get(atype); + realOffset = nextOffset.get(FieldAllocationType.DOUBLE); + nextOffset.put(atype, nextDoubleOffset + allocationTypeSize); + } else if (atype != FieldAllocationType.BAD_ALLOCATION_TYPE) { + if (allocationTypeSpaceCount > 0) { + realOffset = allocationTypeSpaceOffset; + spaceOffset.put(atype, allocationTypeSpaceOffset + allocationTypeSize); + spaceCount.put(atype, allocationTypeSpaceCount - 1); + } else { + int allocationTypeNextOffset = nextOffset.get(atype); + realOffset = allocationTypeNextOffset; + nextOffset.put(atype, allocationTypeNextOffset + allocationTypeSize); + } + } else { + throw new IllegalStateException(); + } + + layoutedFields.add(f.toString()); + result.add(new FieldLayout(f, realOffset, model.sizeOf(f.typeClass()))); + } + } + + // Handle the contended cases. + // + // Each contended field should not intersect the cache line with another contended field. + // In the absence of alignment information, we end up with pessimistically separating + // the fields with full-width padding. + // + // Additionally, this should not break alignment for the fields, so we round the alignment up + // for each field. + if (contendedCount > 0) { + + // if there is at least one contended field, we need to have pre-padding for them + nextPaddedOffset += CONTENDED_PADDING_WIDTH; + + // collect all contended groups + HashSet contendedGroups = new HashSet(); + for (String k : hierarchy) { + + Collection fields = cd.fieldsFor(k); + for (FieldData f : fields) { - int fSize = model.sizeOf(f.typeClass()); - if (fSize != size) continue; - - for (int t = 0; t < Integer.MAX_VALUE; t++) { - if (claimed.get(t * size, (t + 1) * size).isEmpty()) { - claimed.set(t * size, (t + 1) * size); - current.add(new FieldLayout(f, t * size, size)); - break; - } + if (f.isContended()) { + contendedGroups.add(f.contendedGroup()); } } } - result.addAll(current); - if (takeSuperGaps) { - // do nothing - } else if (takeHierarchyGaps) { - // claim only the class body up to the field - int lastSet = claimed.length(); - claimed.set(0, lastSet); - } else { - // claim the entire class body, plus some alignment - int lastSet = claimed.length(); - claimed.set(0, MathUtil.align(lastSet, model.sizeOf("java.lang.Object"))); + for (String currentGroup : contendedGroups) { + + for (String k : hierarchy) { + + Collection fields = cd.fieldsFor(k); + + for (FieldData f : fields) { + + // skip already laid out fields + if (layoutedFields.contains(f.toString())) continue; + + // skip non-contended fields and fields from different group + if (!f.isContended() || !f.contendedGroup().equals(currentGroup)) continue; + + int realOffset = 0; + FieldAllocationType atype = allocationTypeFor(f.refField()); + + if (atype != FieldAllocationType.BAD_ALLOCATION_TYPE) { + int allocationTypeSize = allocationTypeSizes.get(atype); + nextPaddedOffset = MathUtil.align(nextPaddedOffset, allocationTypeSize); + realOffset = nextPaddedOffset; + nextPaddedOffset += allocationTypeSize; + + if (atype == FieldAllocationType.OOP && firstOopOffset == 0) { // Undefined + firstOopOffset = realOffset; + } + } else { + throw new IllegalStateException(); + } + + if (f.contendedGroup().equals("")) { + // Contended group defines the equivalence class over the fields: + // the fields within the same contended group are not inter-padded. + // The only exception is default group, which does not incur the + // equivalence, and so requires intra-padding. + nextPaddedOffset += CONTENDED_PADDING_WIDTH; + } + + result.add(new FieldLayout(f, realOffset, model.sizeOf(f.typeClass()))); + } + } + + // Start laying out the next group. + // Note that this will effectively pad the last group in the back; + // this is expected to alleviate memory contention effects for + // subclass fields and/or adjacent object. + // If this was the default group, the padding is already in place. + if (currentGroup != "") { + nextPaddedOffset += CONTENDED_PADDING_WIDTH; + } } } + // Entire class is contended, pad in the back. + // This helps to alleviate memory contention effects for subclass fields + // and/or adjacent object. + if (isContendedClass) { + nextPaddedOffset += CONTENDED_PADDING_WIDTH; + } + + int notalignedFieldsEnd = nextPaddedOffset; + + int instanceEnd = MathUtil.align(notalignedFieldsEnd, 4); + int instanceSize; if (autoAlign) { int a = 4; for (FieldLayout f : result) { a = Math.max(a, model.sizeOf(f.typeClass())); } - instanceSize = MathUtil.align(claimed.length(), a); + instanceSize = MathUtil.align(instanceEnd / 4, a); } else { - instanceSize = MathUtil.align(claimed.length(), model.objectAlignment()); + instanceSize = MathUtil.align(instanceEnd, model.objectAlignment()); } return new ClassLayout(cd, result, model.headerSize(), instanceSize, true); diff -r 4443d2696dcf -r 72b69400980f jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_26_Hotspot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_26_Hotspot.java Thu Jan 21 02:33:12 2016 +0300 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, Oracle America, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Oracle nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.openjdk.jol.samples; + +import org.openjdk.jol.info.ClassLayout; +import org.openjdk.jol.util.VMSupport; + +import org.openjdk.jol.datamodel.X86_32_DataModel; +import org.openjdk.jol.datamodel.X86_64_COOPS_DataModel; +import org.openjdk.jol.datamodel.X86_64_DataModel; +import org.openjdk.jol.layouters.HotSpotLayouter; +import org.openjdk.jol.layouters.Layouter; +import sun.misc.Contended; + +import static java.lang.System.out; + +/** + * @author Aleksey Shipilev + */ +public class JOLSample_26_Hotspot { + + public static void main(String[] args) throws Exception { + Layouter l; + + l = new HotSpotLayouter(new X86_32_DataModel()); + System.out.println("***** " + l); + System.out.println(ClassLayout.parseClass(A.class, l).toPrintable()); + + l = new HotSpotLayouter(new X86_64_COOPS_DataModel()); + System.out.println("***** " + l); + System.out.println(ClassLayout.parseClass(A.class, l).toPrintable()); + + l = new HotSpotLayouter(new X86_64_DataModel()); + System.out.println("***** " + l); + System.out.println(ClassLayout.parseClass(A.class, l).toPrintable()); + } + + public static class A { + private long value; + public long[] padding = new long[5]; + public Object[] o = new Object[1]; + char c; + } +}