severity 642750 grave
tags 642750 + patch
block 582774 by 642750
thanks



While working on this bug I realized that webkit has yet another bug that prevents it from working on ia64. I filed the separate bug#694971 for that.

I built the libwebkitgtk-3.0-0 package which was configured with --enable-debug. (Wasn't possible with the initial 4GB of memory at all. After a memory upgrade to 16GB it took eleven-and-a-half hour on my box with the -j2 option.)

Just starting epiphany-browser showed a first hint what is going on:
ASSERTION FAILED: isCell()
../Source/JavaScriptCore/runtime/JSValueInlineMethods.h(491) : JSC::JSCell* JSC::JSValue::asCell() const

Webkit uses a variant data type JSValue, which it uses for anything that can be a thing on Java script. It can contain an integer number, a float number or a pointer to an object - this is 'cell'.

It turned out that the 'isCell()' assertion failed for a JSValue that just has been initialized as a pointer.

The arch determines how the JSValue is defined; there are two options (yet), one for any 32-bits arch, the other one for 64-bits archs.

You can see this in Source/JavaScriptCore/runtime/JSValue.h - JSValue defines an embedded data type 'EncodedValueDescriptor' for that:

#if USE(JSVALUE32_64)
    typedef int64_t EncodedJSValue;
#else
    typedef void* EncodedJSValue;
#endif

    union EncodedValueDescriptor {
        int64_t asInt64;
#if USE(JSVALUE32_64)
        double asDouble;
#elif USE(JSVALUE64)
        JSCell* ptr;
#endif

#if CPU(BIG_ENDIAN)
        struct {
            int32_t tag;
            int32_t payload;
        } asBits;
#else
        struct {
            int32_t payload;
            int32_t tag;
        } asBits;
#endif
    };

....

#if USE(JSVALUE32_64)
        /*
* On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
         * form for immediates.
         *
* The encoding makes use of unused NaN space in the IEEE754 representation. Any value * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values * can encode a 51-bit payload. Hardware produced and C-library payloads typically * have a payload of zero. We assume that non-zero payloads are available to encode * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are * all set represents a NaN with a non-zero payload, we can use this space in the NaN * ranges to encode other values (however there are also other ranges of NaN space that
         * could have been selected).
         *
* For JSValues that do not contain a double value, the high 32 bits contain the tag * values listed in the enums below, which all correspond to NaN-space. In the case of * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer * integer or boolean value; in the case of all other tags the payload is 0.
         */
        enum { Int32Tag =        0xffffffff };
        enum { BooleanTag =      0xfffffffe };
        enum { NullTag =         0xfffffffd };
        enum { UndefinedTag =    0xfffffffc };
        enum { CellTag =         0xfffffffb };
        enum { EmptyValueTag =   0xfffffffa };
        enum { DeletedValueTag = 0xfffffff9 };

        enum { LowestTag =  DeletedValueTag };

        uint32_t tag() const;
        int32_t payload() const;
#elif USE(JSVALUE64)
        /*
* On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
         * form for immediates.
         *
* The encoding makes use of unused NaN space in the IEEE754 representation. Any value * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values * can encode a 51-bit payload. Hardware produced and C-library payloads typically * have a payload of zero. We assume that non-zero payloads are available to encode * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are * all set represents a NaN with a non-zero payload, we can use this space in the NaN * ranges to encode other values (however there are also other ranges of NaN space that
         * could have been selected).
         *
* This range of NaN space is represented by 64-bit numbers begining with the 16-bit * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
         * numbers will begin fall in these ranges.
         *
         * The top 16-bits denote the type of the encoded JSValue:
         *
         *     Pointer {  0000:PPPP:PPPP:PPPP
         *              / 0001:****:****:****
         *     Double  {         ...
         *              \ FFFE:****:****:****
         *     Integer {  FFFF:0000:IIII:IIII
         *
* The scheme we have implemented encodes double precision values by performing a * 64-bit integer addition of the value 2^48 to the number. After this manipulation * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF. * Values must be decoded by reversing this operation before subsequent floating point
         * operations my be peformed.
         *
         * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
         *
* The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean, * null and undefined values are represented by specific, invalid pointer values:
         *
         *     False:     0x06
         *     True:      0x07
         *     Undefined: 0x0a
         *     Null:      0x02
         *
         * These values have the following properties:
* - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be * quickly distinguished from all immediate values, including these invalid pointers. * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
         *   same value, allowing null & undefined to be quickly detected.
         *
* No valid JSValue will have the bit pattern 0x0, this is used to represent array * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
         */

// These values are #defines since using static const integers here is a ~1% regression!

// This value is 2^48, used to encode doubles such that the encoded value will begin
        // with a 16-bit pattern within the range 0x0001..0xFFFE.
        #define DoubleEncodeOffset 0x1000000000000ll
        // If all bits in the mask are set, this indicates an integer number,
        // if any but not all are set this value is a double precision number.
        #define TagTypeNumber 0xffff000000000000ll

        // All non-numeric (bool, null, undefined) immediates have bit 2 set.
        #define TagBitTypeOther 0x2ll
        #define TagBitBool      0x4ll
        #define TagBitUndefined 0x8ll
        // Combined integer value for non-numeric immediates.
        #define ValueFalse     (TagBitTypeOther | TagBitBool | false)
        #define ValueTrue      (TagBitTypeOther | TagBitBool | true)
        #define ValueUndefined (TagBitTypeOther | TagBitUndefined)
        #define ValueNull      (TagBitTypeOther)

// TagMask is used to check for all types of immediate values (either number or 'other').
        #define TagMask (TagTypeNumber | TagBitTypeOther)

// These special values are never visible to JavaScript code; Empty is used to represent // Array holes, and for uninitialized JSValues. Deleted is used in hash table code. // These values would map to cell types in the JSValue encoding, but not valid GC cell // pointer should have either of these values (Empty is null, deleted is at an invalid
        // alignment for a GC cell, and in the zero page).
        #define ValueEmpty   0x0ll
        #define ValueDeleted 0x4ll
#endif






USE(JSVALUE64) is true on ia64; USE(JSVALUE32_64) is false.

The code on a true USE(JSVALUE64) uses some sophisticated tricks in order to get everything in a 64-bits wide data type. If you read the comment of the webkit source, you realize that this works as long the high 16-bits of the addresses of any allocated memory are cleared. But when you look at the crash dumps above, you see a lot of addresses which have some upper bits set. This is the reason why decoding of the variant data type fails - the mentioned failed assertion.

(If you think you have a Déjà vu, it is because the Mozilla Java script engine uses a similar trick on 64-bit archs, and has a similar problem on ia64, for example, see the archived bug#659186.)



The proposed patch defines a third option
USE(JSVALUE64W)
which we use *only* on ia64.
It uses an encapsulated union without any trick for the variant data type. This is portable but
- the data type is 128-bits wide,
- Enabling JIT compiler isn't possible - that's not that bad; ia64 doesn't have a JIT compiler.

The patch is for the most recent libwebkitgtk-3.0-0 package of Wheezy.
The patch doesn't change anything on archs other than ia64.


The packages which were built with the patch of this bug report and the one of bug#694971 is here; the tar contains all debs which are created by the libwebkitgtk-3.0-0 source:
http://www.fs-driver.org/debian-ia64/webkitgtk-debs.tar


The patches also fix bug#582774 (seed FTBFS on ia64).

Stephan



Attachment: ia64-wide-ptr.patch
Description: ia64-wide-ptr.patch

Reply via email to