js/src/jsapi-tests/testFindSCCs.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  */
     4 /* This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 #include <stdarg.h>
     9 #include <string.h>
    11 #include "gc/FindSCCs.h"
    12 #include "jsapi-tests/tests.h"
    14 static const unsigned MaxVertices = 10;
    16 using js::gc::GraphNodeBase;
    17 using js::gc::ComponentFinder;
    19 struct TestNode : public GraphNodeBase<TestNode>
    20 {
    21     unsigned   index;
    22     bool       hasEdge[MaxVertices];
    24     void findOutgoingEdges(ComponentFinder<TestNode> &finder);
    25 };
    27 static TestNode Vertex[MaxVertices];
    29 void
    30 TestNode::findOutgoingEdges(ComponentFinder<TestNode> &finder)
    31 {
    32     for (unsigned i = 0; i < MaxVertices; ++i) {
    33         if (hasEdge[i])
    34             finder.addEdgeTo(&Vertex[i]);
    35     }
    36 }
    38 BEGIN_TEST(testFindSCCs)
    39 {
    40     // no vertices
    42     setup(0);
    43     run();
    44     CHECK(end());
    46     // no edges
    48     setup(1);
    49     run();
    50     CHECK(group(0, -1));
    51     CHECK(end());
    53     setup(3);
    54     run();
    55     CHECK(group(2, -1));
    56     CHECK(group(1, -1));
    57     CHECK(group(0, -1));
    58     CHECK(end());
    60     // linear
    62     setup(3);
    63     edge(0, 1);
    64     edge(1, 2);
    65     run();
    66     CHECK(group(0, -1));
    67     CHECK(group(1, -1));
    68     CHECK(group(2, -1));
    69     CHECK(end());
    71     // tree
    73     setup(3);
    74     edge(0, 1);
    75     edge(0, 2);
    76     run();
    77     CHECK(group(0, -1));
    78     CHECK(group(2, -1));
    79     CHECK(group(1, -1));
    80     CHECK(end());
    82     // cycles
    84     setup(3);
    85     edge(0, 1);
    86     edge(1, 2);
    87     edge(2, 0);
    88     run();
    89     CHECK(group(0, 1, 2, -1));
    90     CHECK(end());
    92     setup(4);
    93     edge(0, 1);
    94     edge(1, 2);
    95     edge(2, 1);
    96     edge(2, 3);
    97     run();
    98     CHECK(group(0, -1));
    99     CHECK(group(1, 2, -1));
   100     CHECK(group(3, -1));
   101     CHECK(end());
   103     // remaining
   105     setup(2);
   106     edge(0, 1);
   107     run();
   108     CHECK(remaining(0, 1, -1));
   109     CHECK(end());
   111     setup(2);
   112     edge(0, 1);
   113     run();
   114     CHECK(group(0, -1));
   115     CHECK(remaining(1, -1));
   116     CHECK(end());
   118     setup(2);
   119     edge(0, 1);
   120     run();
   121     CHECK(group(0, -1));
   122     CHECK(group(1, -1));
   123     CHECK(remaining(-1));
   124     CHECK(end());
   126     return true;
   127 }
   129 unsigned vertex_count;
   130 ComponentFinder<TestNode> *finder;
   131 TestNode *resultsList;
   133 void setup(unsigned count)
   134 {
   135     vertex_count = count;
   136     for (unsigned i = 0; i < MaxVertices; ++i) {
   137         TestNode &v = Vertex[i];
   138         v.gcNextGraphNode = nullptr;
   139         v.index = i;
   140         memset(&v.hasEdge, 0, sizeof(v.hasEdge));
   141     }
   142 }
   144 void edge(unsigned src_index, unsigned dest_index)
   145 {
   146     Vertex[src_index].hasEdge[dest_index] = true;
   147 }
   149 void run()
   150 {
   151     finder = new ComponentFinder<TestNode>(rt->mainThread.nativeStackLimit[js::StackForSystemCode]);
   152     for (unsigned i = 0; i < vertex_count; ++i)
   153         finder->addNode(&Vertex[i]);
   154     resultsList = finder->getResultsList();
   155 }
   157 bool group(int vertex, ...)
   158 {
   159     TestNode *v = resultsList;
   161     va_list ap;
   162     va_start(ap, vertex);
   163     while (vertex != -1) {
   164         CHECK(v != nullptr);
   165         CHECK(v->index == unsigned(vertex));
   166         v = v->nextNodeInGroup();
   167         vertex = va_arg(ap, int);
   168     }
   169     va_end(ap);
   171     CHECK(v == nullptr);
   172     resultsList = resultsList->nextGroup();
   173     return true;
   174 }
   176 bool remaining(int vertex, ...)
   177 {
   178     TestNode *v = resultsList;
   180     va_list ap;
   181     va_start(ap, vertex);
   182     while (vertex != -1) {
   183         CHECK(v != nullptr);
   184         CHECK(v->index == unsigned(vertex));
   185         v = (TestNode *)v->gcNextGraphNode;
   186         vertex = va_arg(ap, int);
   187     }
   188     va_end(ap);
   190     CHECK(v == nullptr);
   191     resultsList = nullptr;
   192     return true;
   193 }
   195 bool end()
   196 {
   197     CHECK(resultsList == nullptr);
   199     delete finder;
   200     finder = nullptr;
   201     return true;
   202 }
   203 END_TEST(testFindSCCs)
   205 struct TestNode2 : public GraphNodeBase<TestNode2>
   206 {
   207     TestNode2 *edge;
   209     TestNode2() :
   210         edge(nullptr)
   211     {
   212     }
   214     void
   215     findOutgoingEdges(ComponentFinder<TestNode2> &finder) {
   216         if (edge)
   217             finder.addEdgeTo(edge);
   218     }
   219 };
   221 BEGIN_TEST(testFindSCCsStackLimit)
   222 {
   223     /*
   224      * Test what happens if recusion causes the stack to become full while
   225      * traversing the graph.
   226      *
   227      * The test case is a large number of vertices, almost all of which are
   228      * arranged in a linear chain.  The last few are left unlinked to exercise
   229      * adding vertices after the stack full condition has already been detected.
   230      *
   231      * Such an arrangement with no cycles would normally result in one group for
   232      * each vertex, but since the stack is exhasted in processing a single group
   233      * is returned containing all the vertices.
   234      */
   235     const unsigned max = 1000000;
   236     const unsigned initial = 10;
   238     TestNode2 *vertices = new TestNode2[max]();
   239     for (unsigned i = initial; i < (max - 10); ++i)
   240         vertices[i].edge = &vertices[i + 1];
   242     ComponentFinder<TestNode2> finder(rt->mainThread.nativeStackLimit[js::StackForSystemCode]);
   243     for (unsigned i = 0; i < max; ++i)
   244         finder.addNode(&vertices[i]);
   246     TestNode2 *r = finder.getResultsList();
   247     CHECK(r);
   248     TestNode2 *v = r;
   250     unsigned count = 0;
   251     while (v) {
   252         ++count;
   253         v = v->nextNodeInGroup();
   254     }
   255     CHECK(count == max - initial);
   257     count = 0;
   258     v = r->nextGroup();
   259     while (v) {
   260         ++count;
   261         CHECK(!v->nextNodeInGroup());
   262         v = v->nextGroup();
   263     }
   265     delete [] vertices;
   266     return true;
   267 }
   268 END_TEST(testFindSCCsStackLimit)

mercurial