Bug 18672 - SQUIRRELFISH: codegen fails with a large number of temporaries
Summary: SQUIRRELFISH: codegen fails with a large number of temporaries
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Oliver Hunt
URL:
Keywords:
Depends on:
Blocks: 18624
  Show dependency treegraph
 
Reported: 2008-04-21 17:16 PDT by Cameron Zwarich (cpst)
Modified: 2008-04-23 12:41 PDT (History)
4 users (show)

See Also:


Attachments
Patch-fu! (12.70 KB, patch)
2008-04-22 21:59 PDT, Oliver Hunt
no flags Details | Formatted Diff | Diff
Second run (13.45 KB, patch)
2008-04-23 01:27 PDT, Oliver Hunt
ggaren: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Cameron Zwarich (cpst) 2008-04-21 17:16:56 PDT
On a number of the JavaScriptCore tests, SquirrelFish fails with an assertion during codegen if there is a large number of temporaries. These failures do not get seem to get reported by run-javascriptcore-tests. An example is ecma/Array/15.4.5.2-2.js, which fails with the following assertion:

ASSERTION FAILED: m_temporaries.size() < m_temporaries.capacity()
(./VM/CodeGenerator.cpp:296 KJS::RegisterID* KJS::CodeGenerator::newTemporary())

Many of the array tests fail for the same reason.
Comment 1 Maciej Stachowiak 2008-04-21 17:31:02 PDT
Geoff and I agree that a good way to do this would be to use a segmented array for the temporaries (so they don't move but we still have the ability to allocate more).
Comment 2 Cameron Zwarich (cpst) 2008-04-21 18:06:54 PDT
(In reply to comment #1)
> Geoff and I agree that a good way to do this would be to use a segmented array
> for the temporaries (so they don't move but we still have the ability to
> allocate more).

I agree with this suggestion.
Comment 3 Oliver Hunt 2008-04-22 21:59:32 PDT
Created attachment 20763 [details]
Patch-fu!
Comment 4 Oliver Hunt 2008-04-23 01:27:23 PDT
Created attachment 20766 [details]
Second run

Second run, now actually returns memory, SunSpider reports a 0.4% progression but that seems unlikely to be "real"
Comment 5 Geoffrey Garen 2008-04-23 07:45:52 PDT
Comment on attachment 20766 [details]
Second run

+		A7C31DA90DBEBA4300FDF8EB /* SegmentedVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C31DA80DBEBA4300FDF8EB /* SegmentedVector.h */; };
+		A7C31DAA0DBEBA4300FDF8EB /* SegmentedVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A7C31DA80DBEBA4300FDF8EB /* SegmentedVector.h */; };

SegmentedVector is really a component of the compiler, not the VM. I think it
belongs in the compiler folder.

+            if (!(m_size % SegmentSize) && m_size >= SegmentSize)

Would

if (!(m_size % SegmentSize) && m_size > 0)

do the same job? If so, I think it would be clearer.

+        void removeLast()
+        {
+            ASSERT(m_size);
+            m_size--;
+            m_buffers.last()->removeLast();
+            if (!(m_size % SegmentSize) && m_size >= SegmentSize) {
+                delete m_buffers.last();
+                m_buffers.removeLast();
+            }
+        }

Technically, if you kept adding and removing an item at the segement boundary,
this algorithm would give you really bad performance, because it would
repeatedly malloc/free a large block. You could fix the problem by keeping a
size and a capacity, just like Vector does. I don't think this is a blocker to
landing, though, since you'd have to get pretty unlucky to hit this case during
codegen.

+            if (index < SegmentSize)
+                return m_inlineBuffer[index];
+            return m_buffers[index / SegmentSize]->at(index % SegmentSize);

Why do we need to special-case the inline buffer here? Shouldn't the math "just
work"? I'd recommend removing the special case.

+        void shrink(size_t size)
+        {
...
+        }
+
+        void grow(size_t size)
+        {
...
+        }

These methods look a little long for inlining. I'd recommend moving them out of
the class declaration.

+        void grow(size_t size)
+        {
+            ASSERT(size > m_size);
+            if (size <= SegmentSize) {
+                m_inlineBuffer.resize(size);

You can call "grow" here instead of "resize". Same thing in a few other places
in this function.

+        Segment m_inlineBuffer;
+        Vector<Segment*, 32> m_buffers;

Quibble: is it a "segment" or a "buffer"? I would call these "m_inlineSegment"
and "m_segments".

Nice work.

r=me
Comment 6 Oliver Hunt 2008-04-23 12:41:13 PDT
> SegmentedVector is really a component of the compiler, not the VM. I think it
> belongs in the compiler folder.
>
There is no Compiler directory -- I did put it in the Compiler group (in xcode), other things (like CodeGenerator.{h,cpp} are there as well.
 
> +            if (!(m_size % SegmentSize) && m_size >= SegmentSize)
> 
> Would
> 
> if (!(m_size % SegmentSize) && m_size > 0)

Fixed

> 
> do the same job? If so, I think it would be clearer.
> 
> +        void removeLast()
> +        {
> +            ASSERT(m_size);
> +            m_size--;
> +            m_buffers.last()->removeLast();
> +            if (!(m_size % SegmentSize) && m_size >= SegmentSize) {
> +                delete m_buffers.last();
> +                m_buffers.removeLast();
> +            }
> +        }
> 
> Technically, if you kept adding and removing an item at the segement boundary,
> this algorithm would give you really bad performance, because it would
> repeatedly malloc/free a large block. You could fix the problem by keeping a
> size and a capacity, just like Vector does. I don't think this is a blocker to
> landing, though, since you'd have to get pretty unlucky to hit this case during
> codegen.

Yeah, i know, however in the general case you do not have 512 temporaries so i thought this would be okay (at least for now)

> 
> +            if (index < SegmentSize)
> +                return m_inlineBuffer[index];
> +            return m_buffers[index / SegmentSize]->at(index % SegmentSize);
> 
> Why do we need to special-case the inline buffer here? Shouldn't the math "just
> work"? I'd recommend removing the special case.
Performance, no other reason

> 
> +        void shrink(size_t size)
> +        {
> ...
> +        }
> +
> +        void grow(size_t size)
> +        {
> ...
> +        }
> 
> These methods look a little long for inlining. I'd recommend moving them out of
> the class declaration.
> 
> +        void grow(size_t size)
> +        {
> +            ASSERT(size > m_size);
> +            if (size <= SegmentSize) {
> +                m_inlineBuffer.resize(size);
> 
> You can call "grow" here instead of "resize". Same thing in a few other places
> in this function.

That's a perf regression :-/

> 
> +        Segment m_inlineBuffer;
> +        Vector<Segment*, 32> m_buffers;
> 
> Quibble: is it a "segment" or a "buffer"? I would call these "m_inlineSegment"
> and "m_segments".

Agreed, and m_inlineSegment for good measure

> 
> Nice work.
> 
> r=me
> 

Committer r32444