[webkit-dev] Question about javascriptcore garbage collection

Krzysztof Kowalczyk kkowalczyk at gmail.com
Sat Sep 3 12:56:51 PDT 2005


To answer my own question: the problem is that ValueImp has no virtual
functions (=> no virtual table) and AllocatedValueImp does. That means
that cast between ValueImp* and AllocatedValueImp* involve
adding/substracting 4 bytes to the pointer of the object, since, at
least in visual c, pointer to vtable is the first member of the
object. AllocatedValueImp * is allocated at CollectorCell boundary,
but when casted to  ValueImp * it is no longer recognized by GC.

Here's a small test program that shows this. See the last 3 addresses
in the output for how the address changes depending on the type of
pointer.

So I devised another way of fixing the problem: simply marking
ValueImp::~ValueImp as virtual also fixes crashes for me.

So the remaining question is: what is the behaviour on Mac/gcc ? I
would aprecciate if a mac person would run this and posted the
results. On my win machine it says:

C:\kjk\src\ext\libs\webcore-apple\JavaScriptCore>inh-test.exe
justVal         : 0x322bc0
num             : 0x322bd0
numCasted       : 0x322bd4
numDowncasted   : 0x322bd0
jsNumber num    : 0x320f60
jsNumberAsVI    : 0x320f64
jsNumberAsAVI   : 0x320f60

On a separate note: I don't see why ValueImp couldn't be eliminated
alltogether and its functionality folded in  AllocatedValueImp (which
would also solve the problem).

Test program:

#include <stdio.h>

class ValueImp {
    friend class AllocatedValueImp; // so it can derive from this class
public:
    ValueImp() {};
    ~ValueImp() {};
    void mark();
    bool marked() const;

    AllocatedValueImp *downcast();
    const AllocatedValueImp *downcast() const;
};

class SimpleNumber {
public:
  static inline bool is(const ValueImp *imp) { return false; }
};

class AllocatedValueImp : public ValueImp {
    friend class NumberImp;
private:
    AllocatedValueImp() {};
    virtual ~AllocatedValueImp() {};
public:
    virtual void mark();
    bool marked() const;
private:
    bool m_marked;
};

class NumberImp : public AllocatedValueImp {
  public:
    NumberImp(double v) : val(v) { }
  private:
    virtual ~NumberImp() {};
    NumberImp() { }
    double val;
};

inline void ValueImp::mark()
{
    if (!SimpleNumber::is(this))
        downcast()->mark();
}

inline bool ValueImp::marked() const
{
    return SimpleNumber::is(this) || downcast()->marked();
}

inline AllocatedValueImp *ValueImp::downcast()
{
    return static_cast<AllocatedValueImp *>(this);
}

inline const AllocatedValueImp *ValueImp::downcast() const
{
    return static_cast<const AllocatedValueImp *>(this);
}

inline bool AllocatedValueImp::marked() const
{
    return m_marked;
}

inline void AllocatedValueImp::mark()
{
    m_marked = true;
}

ValueImp *jsNumber(double d)
{
    NumberImp *num = new NumberImp(d);
    printf("jsNumber num    : 0x%x\n", num);
    return num;
}

int main(int argc, char **argv)
{
    ValueImp  *justVal = new ValueImp();
    AllocatedValueImp *num = new NumberImp(15.0);
    ValueImp *numCasted = static_cast<ValueImp*>(num);
    AllocatedValueImp *numDowncasted = numCasted->downcast();

    printf("justVal         : 0x%x\n", justVal);
    printf("num             : 0x%x\n", num);
    printf("numCasted       : 0x%x\n", numCasted);
    printf("numDowncasted   : 0x%x\n", numDowncasted);

    ValueImp *jsNumberAsValueImp = jsNumber(5.0);
    printf("jsNumberAsVI    : 0x%x\n", jsNumberAsValueImp);
    AllocatedValueImp *asAllocatedValueImp = jsNumberAsValueImp->downcast();
    printf("jsNumberAsAVI   : 0x%x\n", asAllocatedValueImp);
    return 0;
}



More information about the webkit-dev mailing list