On Wed, May 1, 2013 at 9:30 PM, Phil Race <philip.r...@oracle.com> wrote:
> Volker .. thanks for the patch looks good although I ask
> that you break the source code lines at no more than 80 chars ..
> that's the norm/standard we have always used
>

I read the guidlines but after I realized that some of the files I
changed already contain lines with more than 130 characters I thought
that the guildines may be antiquated in that respect :) Nevertheless,
I'm not against coding standards at all, so please find the '80
chars'-version of my patch below:

http://cr.openjdk.java.net/~simonis/webrevs/7191872

> There actually is an open bug on this you can use :-
>
> 7191872: The panel does not include any information for each case on
> solaris11-sparc.
>

Thanks. I've used it in the new webrev.
Unfortunately searching the bug database for 'xrender' only returns a
single hit and omits the bug you mentioned. But that's a totally
different discussion :)

Regards,
Volker

>
> -phil.
>
>
> On 4/26/2013 7:02 AM, Volker Simonis wrote:
>>
>> Hi,
>>
>> I've found and fixed a problem of the XRender pipeline on 64-bit
>> Big-endian architectures which leads to the effect that all AWT/Swing
>> applications will run as expected but won't actually display any
>> character glyphs at all! This seems to be a "day-one" bug which still
>> exists in both, JDK7 and JDK8 but probably didn't pop up until now
>> because the XRender backend wasn't enabled by default. This has
>> however changed recently in JDK8.
>>
>> Could somebody please open a bug for this issue and review the change:
>>
>> http://cr.openjdk.java.net/~simonis/webrevs/webrev_xrender.v1/
>>
>> The fix is small and straightforward.
>> You can read the full story below (or the HTML-version in the webrev
>> for a better reading experience).
>>
>> Thank you and best regards,
>> Volker
>>
>>
>>
>> Problem description
>>
>> The XRender backend writes some native data-structures which have the
>> size of a native pointer (i.e. 32-bit on 32-bit architectures and
>> 64-bit on 64-bit architectures) by using Unsafe.putInt(). This is of
>> course not safe and breaks on 64-bit Big-endian architectures like
>> SPARC, PPC64 or HPUX/IA64. The concrete problem is in the method
>> setGlyphID in src/solaris/classes/sun/font/XRGlyphCacheEntry.java:
>>
>> public static void setGlyphID(long glyphInfoPtr, int id) {
>>      StrikeCache.unsafe.putInt(glyphInfoPtr + StrikeCache.cacheCellOffset,
>> id);
>> }
>>
>> which writes the offending field and in the function
>> Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative in
>> src/solaris/native/sun/java2d/x11/XRBackendNative.c which reads this
>> field:
>>
>> for (i=0; i < glyphCnt; i++) {
>>    GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]);
>>
>>    gid[i] = (Glyph) (0x0ffffffffL & ((unsigned long)(jginfo->cellInfo)));
>>
>> Actually, they both access the cellInfo field of a GlypInfo structure
>> which has the size of a native pointer (see
>> src/share/native/sun/font/fontscalerdefs.h):
>>
>> struct GlyphInfo {
>>      float advanceX;
>>      float advanceY;
>>      UInt16 width;
>>      UInt16 height;
>>      UInt16 rowBytes;
>>      UInt8 managed;
>>      float topLeftX;
>>      float topLeftY;
>>      void *cellInfo;
>>      UInt8 *image;
>> }
>>
>> The native reader reads the field as a void* and casts it into an
>> unsigned long. On Big-endian architectures this shifts the integer
>> value which had been previously written in setGlyphID() by 32 bits to
>> the left such that the final 'anding' with 0x0ffffffffL will always
>> lead to a zero result (on Little-endian architectures there's no
>> problem because the 4-byte integer value lies in the 'right' half of
>> the 8-byte long value).
>>
>> How to reproduce the problem
>>
>> This finally leads to the effect that all AWT/Swing applications will
>> run as expected but won't actually display any character glyphs at
>> all! This behavior is reproducible with every JDK7 and JDK8. You just
>> have to set the property -Dsun.java2d.xrender=True and make sure that
>> the actual Xserver which displays the application window really
>> supports the XRender extension. Using -Dsun.java2d.xrender=True (with
>> capital 'T') will print a debugging line which confirms whether the
>> XRender pipeline will be used ('XRender pipeline enabled') or not
>> ('Could not enable XRender pipeline').
>>
>> Notice that the XRender pipeline was switched off by default in JDK7
>> but is currently switched on by default in JDK8. However if the
>> displaying X-server doesn't support XRender there's always a silent
>> fallback to the plain X11 rendering pipeline. So you need an XRender
>> capable X server to reproduce this problem.
>>
>> How to fix the problem
>>
>> Fixing the problem is easy: we just have to replace the offending
>> Unsafe.putInt()/Unsafe.getInt() accesses with corresponding
>> Unsafe.putAddress()/Unsafe.getAddress() calls. These routines
>> write/read 4 byte in 32-bit VMs and 8 byte on 64-bit VMs (actually
>> they read/write Unsafe.addressSize() bytes which corresponds to the
>> mentioned values).
>>
>> Other cleanups in the patch
>>
>> Once I've fixed the problem, I've also cleaned up several other
>> occurrences of the following pattern:
>>
>> long pixelDataAddress;
>> if (StrikeCache.nativeAddressSize == 4) {
>>      pixelDataAddress = 0xffffffff &
>> StrikeCache.unsafe.getInt(glyphInfoPtr + StrikeCache.pixelDataOffset);
>> } else {
>>      pixelDataAddress = StrikeCache.unsafe.getLong(glyphInfoPtr +
>> StrikeCache.pixelDataOffset);
>> }
>> long pixelDataAddress = StrikeCache.unsafe.getAddress(glyphInfoPtr +
>> StrikeCache.pixelDataOffset);
>>
>> The intention of this code is to load a native pointer and store it
>> into a Java long variable. On 32-bit architectures it uses
>> Unsafe.getInt() to read the value and masks the result with 0xffffffff
>> after converting it into a Java long value (which is actually the same
>> as doing a zero-extension of a 32-bit value during the conversion into
>> a 64-bit value). On 64-bit architectures it simply uses
>> Unsafe.getLong() to read the value.
>>
>> The previous code can be simplified into a single expression by always
>> using Unsafe.getAddress():
>>
>> long pixelDataAddress = StrikeCache.unsafe.getAddress(glyphInfoPtr +
>> StrikeCache.pixelDataOffset);
>>
>> because Unsafe.getAddress() does exactly the same thing: it reads a
>> native pointer and returns it as a Java long value. In the case where
>> the native pointer is less than 64 bits wide, it is extended as an
>> unsigned number to a Java long (see JavaDoc of
>> sun.misc.Unsafe.getAddress()).
>>
>> I've also simplified the following line in the function
>> Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative in
>> src/solaris/native/sun/java2d/x11/XRBackendNative.c:
>>
>> -      gid[i] = (Glyph) (0x0ffffffffL & ((unsigned
>> long)(jginfo->cellInfo)));
>> +      // 'jginfo->cellInfo' is of type 'void*' (see definition of
>> 'GlyphInfo' in fontscalerdefs.h)
>> +      // 'Glyph' is typedefed to 'unsigned long' (see
>> http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt)
>> +      // Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ?
>> +      gid[i] = (Glyph) (jginfo->cellInfo);
>>
>> because Glyph is typedefed to unsigned long anyway. The
>> 'zero-extension' of the result is unnecessary as well because we're
>> actually reading an integer value here and not a pointer.
>
>

Reply via email to