[Vm-dev] Re: [Cog] Strange inliner behavior

Eliot Miranda eliot.miranda at gmail.com
Sun Jul 31 16:48:41 UTC 2011


Hi Igor,

    this is simply because the inliner can only inline an expression in an
expression context.  Since sizeBitsOf: is written as multiple statements it
can only be inlined in a statement context.
 Here's NewObjectMemory>sizeBitsOf: with the statements numbered:

sizeBitsOf: oop
"Answer the number of bytes in the given object, including its base header,
rounded up to an integral number of words."
"Note: byte indexable objects need to have low bits subtracted from this
size."
<inline: true>
| header |
1. header := self baseHeader: oop.
2. ^(header bitAnd: TypeMask) = HeaderTypeSizeAndClass
ifTrue: [(self sizeHeader: oop) bitAnd: LongSizeMask]
ifFalse: [header bitAnd: SizeMask]

Here's StackInterpreter>printNameOfClass:count:, with the occurrence of
sizeBitsOf: in an expression context:

printNameOfClass: classOop count: cnt
"Details: The count argument is used to avoid a possible infinite recursion
if classOop is a corrupted object."
<inline: false>
(classOop = 0 or: [cnt <= 0]) ifTrue: [^self print: 'bad class'].
e: ((objectMemory sizeBitsOf: classOop) = metaclassSizeBytes
  and: [metaclassSizeBytes > (thisClassIndex * BytesPerWord)]) "(Metaclass
instSize * 4)"
ifTrue: [self printNameOfClass: (objectMemory fetchPointer: thisClassIndex
ofObject: classOop) count: cnt - 1.
self print: ' class']
ifFalse: [self printStringOf: (objectMemory fetchPointer: classNameIndex
ofObject: classOop)]

With sizeBitsOf: defined as above this translates to:

static void
printNameOfClasscount(sqInt classOop, sqInt cnt)
{
if ((classOop == 0)
 || (cnt <= 0)) {
print("bad class"); return;
}
if (((sizeBitsOf(classOop)) == GIV(metaclassSizeBytes))
 && (GIV(metaclassSizeBytes) > (GIV(thisClassIndex) * BytesPerWord))) {
printNameOfClasscount(longAt((classOop + BaseHeaderSize) +
(GIV(thisClassIndex) << ShiftForWord)), cnt - 1);
print(" class");
}
else {
printStringOf(longAt((classOop + BaseHeaderSize) + (GIV(classNameIndex) <<
ShiftForWord)));
}
}

But if one changes the definition of sizeBitsOf: to an expression,
necessitating two references through oop, to:

sizeBitsOf: oop
"Answer the number of bytes in the given object, including its base header,
rounded up to an integral number of words."
"Note: byte indexable objects need to have low bits subtracted from this
size."
<inline: true>
^((self baseHeader: oop) bitAnd: TypeMask) = HeaderTypeSizeAndClass
ifTrue: [(self sizeHeader: oop) bitAnd: LongSizeMask]
ifFalse: [(self baseHeader: oop) bitAnd: SizeMask]

then StackInterpreter>printNameOfClass:count: translates to

static void
printNameOfClasscount(sqInt classOop, sqInt cnt)
{
if ((classOop == 0)
 || (cnt <= 0)) {
print("bad class"); return;
}
if ((((((longAt(classOop)) & TypeMask) == HeaderTypeSizeAndClass
? (longAt(classOop - (BytesPerWord * 2))) & LongSizeMask
: (longAt(classOop)) & SizeMask)) == GIV(metaclassSizeBytes))
 && (GIV(metaclassSizeBytes) > (GIV(thisClassIndex) * BytesPerWord))) {
printNameOfClasscount(longAt((classOop + BaseHeaderSize) +
(GIV(thisClassIndex) << ShiftForWord)), cnt - 1);
print(" class");
}
else {
printStringOf(longAt((classOop + BaseHeaderSize) + (GIV(classNameIndex) <<
ShiftForWord)));
}
}


So (David) this isn't so much a bug as a limitation of the inliner.

Of course in an expression context it could be translated as

static void
printNameOfClasscount(sqInt classOop, sqInt cnt)
{
| header |
if ((classOop == 0)
 || (cnt <= 0)) {
print("bad class"); return;
}
if (((header = longAt(classOop),
 ((header & TypeMask) == HeaderTypeSizeAndClass
? (longAt(classOop - (BytesPerWord * 2))) & LongSizeMask
: header & SizeMask)) == GIV(metaclassSizeBytes))
 && (GIV(metaclassSizeBytes) > (GIV(thisClassIndex) * BytesPerWord))) {
printNameOfClasscount(longAt((classOop + BaseHeaderSize) +
(GIV(thisClassIndex) << ShiftForWord)), cnt - 1);
print(" class");
}
else {
printStringOf(longAt((classOop + BaseHeaderSize) + (GIV(classNameIndex) <<
ShiftForWord)));
}
}

and I think the changes I made recently to
TStmtListNode>emitCCodeAsArgumentOn:level:generator: are what's required.
 You simply have to track down where in the inliner it makes the
determination as to whether the expression can be inlined.


HTH
Eliot

On Sat, Jul 30, 2011 at 8:53 PM, Igor Stasenko <siguctua at gmail.com> wrote:

>
> if instead i do like that:
>
> size := self sizeBitsOf: op1.
> sz2 := self sizeBitsOf: op2.
> size = sz2 ifFalse: [   ^ false ].
>
>
> then it inlines both calls.
>
> On 31 July 2011 05:49, Igor Stasenko <siguctua at gmail.com> wrote:
> > Here the slang code:
> >
> >        size := self sizeBitsOf: op1.
> >        size = (self sizeBitsOf: op2) ifFalse: [
> >                ^ false ].
> >
> > And here translated code:
> >
> >        /* begin sizeBitsOf: */
> >        header = longAt(op1);
> >        size = ((header & TypeMask) == HeaderTypeSizeAndClass
> >                ? (longAt(op1 - (BytesPerWord * 2))) & LongSizeMask
> >                : header & SizeMask);
> >        if (!(size == (sizeBitsOf(op2)))) {
> >                return 0;
> >        }
> >
> > as you can see it inlining first, but refuses to inline second one.
> >
> >
> > --
> > Best regards,
> > Igor Stasenko AKA sig.
> >
>
>
>
> --
> Best regards,
> Igor Stasenko AKA sig.
>



-- 
best,
Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20110731/06d6c307/attachment.htm


More information about the Vm-dev mailing list