Branch: Tag:

2000-06-09

2000-06-09 22:17:28 by Martin Stjernholm <mast@lysator.liu.se>

A bunch of new gc tests.

Rev: src/testsuite.in:1.298

1: - test_true([["$Id: testsuite.in,v 1.297 2000/06/06 22:51:55 hubbe Exp $"]]); + test_true([["$Id: testsuite.in,v 1.298 2000/06/09 22:17:28 mast Exp $"]]);      cond([[all_constants()->_verify_internals]],   [[
1677:    test_any([[object o=class c {object o;}(); o->o=o; gc(); o=0; return gc() > 0; ]],1);    test_any([[mapping m=([]); m[m]=m; gc(); m=0; return gc() > 0; ]],1);    test_any([[multiset m=(<>); m[m]=1; gc(); m=0; return gc() > 0; ]],1); +  test_any([[{ + #if !constant (_debug) +  int _debug (int d) {return 0;}; + #endif +  // Must turn off debug in this test or else we'll get extra +  // references to p in the backlog. +  int dlevel = _debug (0); +  program p=compile_string("constant a=({0});"); +  object o=p(); +  o->a[0]=p; +  gc(); +  p=o=0; +  _debug (dlevel); +  return gc() > 0; +  }]], 1);       test_any([[gc();    int q=lambda() { mixed foo; foo=lambda() { return foo; }; return 1; }();
1755:    }    }()->test();    ]]) +  +  test_any([[{ +  array a = ({({0})}); a[0][0] = a; +  gc(); a = 0; return gc() > 0; +  }]], 1) +  +  test_any([[{ +  class Dead {object o;}; +  object o = Dead(); o->o = Dead(); o->o->o = o; +  gc(); o = 0; return gc() > 0; +  }]], 1) +  test_any([[{ +  class Live {object o; void destroy() {}}; +  object o = Live(); o->o = Live(); o->o->o = o; +  gc(); o = 0; return gc() > 0; +  }]], 1) +  test_any([[{ +  class Dead {object o;}; +  class Live {object o; void destroy() {}}; +  object o = Dead(); o->o = Live(); o->o->o = o; +  gc(); o = 0; return gc() > 0; +  }]], 1) +  test_any([[{ +  class Dead {object o;}; +  class Live {object o; void destroy() {}}; +  object o = Live(); o->o = Dead(); o->o->o = o; +  gc(); o = 0; return gc() > 0; +  }]], 1) +  +  test_any_equal([[{ +  class Live {object o; void destroy() {}}; +  array a = set_weak_flag(({Live()}), 1); +  gc(); return a; +  }]], ({0})) +  test_any_equal([[{ +  class Live {object o; void destroy() {}}; +  multiset l = set_weak_flag((<Live()>), 1); +  gc(); return l; +  }]], (<>)) +  test_any_equal([[{ +  class Live {object o; void destroy() {}}; +  mapping m = set_weak_flag(([0: Live()]), 1); +  gc(); return m; +  }]], ([])) +  test_any_equal([[{ +  class Live {object o; void destroy() {}}; +  mapping m = set_weak_flag(([Live(): 0]), 1); +  gc(); return m; +  }]], ([])) +  test_any_equal([[{ +  array a = set_weak_flag(({4711, 0x54325827a124*0x12348795482485425}), 1); +  gc(); return a; +  }]], ({4711, 0x54325827a124*0x12348795482485425})) +  +  test_any([[{ +  class Dead {object o;}; +  object o = Dead(); o->o = Dead(); +  array a = set_weak_flag(({o}), 1); +  gc(); o = 0; return gc() > 0; +  }]], 1) +  test_any([[{ +  class Dead {object o;}; +  class Live {object o; void destroy() {}}; +  object o = Live(); o->o = Dead(); +  array a = set_weak_flag(({o}), 1); +  gc(); o = 0; return gc() > 0; +  }]], 1) +  test_any([[{ +  class Dead {object o;}; +  class Live {object o; void destroy() {}}; +  object o = Dead(); o->o = Live(); +  array a = set_weak_flag(({o}), 1); +  gc(); o = 0; return gc() > 0; +  }]], 1) +  +  test_do([[{ +  int got_error = 0; +  array(string) destruct_order; +  add_constant ("destructing", lambda (string id) {destruct_order += ({id});}); +  add_constant ("my_error", lambda (string s, mixed... args) { +  if (!got_error) werror ("\n"); +  werror (s, @args); +  got_error = 1; +  }); +  program Dead = compile_string (#" +  string id; +  void create (int i) {id = sprintf (\"dead[%d]\", i);} +  mixed a = 1, b = 1; // Mustn't be zero at destruct time. +  mixed x, y; +  array v = set_weak_flag (({1}), 1); // Mustn't be zero at destruct time. +  array w = set_weak_flag (({0, 0}), 1); +  function(object:mixed) checkfn; +  void check_live (mapping(object:int) checked) { +  //werror (\"check_live %s\\n\", id); +  checked[this_object()] = 1; +  if (!a) my_error (id + \"->a got destructed too early.\\n\"); +  else if (!b) my_error (id + \"->b got destructed too early.\\n\"); +  else if (!v[0]) my_error (id + \"->v[0] got destructed too early.\\n\"); +  else if (functionp (checkfn) && !checkfn (this_object())) +  my_error (id + \"->checkfn failed.\\n\"); +  else { +  if (objectp (a) && !checked[a]) a->check_live (checked); +  if (objectp (b) && !checked[b]) b->check_live (checked); +  if (objectp (x) && !checked[x]) x->check_live (checked); +  if (objectp (y) && !checked[y]) y->check_live (checked); +  if (objectp (v[0]) && !checked[v[0] ]) v[0]->check_live (checked); +  if (objectp (w[0]) && !checked[w[0] ]) w[0]->check_live (checked); +  if (objectp (w[1]) && !checked[w[1] ]) w[1]->check_live (checked); +  } +  //werror (\"check_live %s done\\n\", id); +  } +  "); +  add_constant ("Dead", Dead); +  program Live = compile_string (#" +  inherit Dead; +  void create (int i) {id = sprintf (\"live[%d]\", i);} +  void destroy() { +  destructing (id); +  //werror (\"destroy %s\\n\", id); +  check_live (([])); +  } +  "); +  add_constant ("Live", Live); +  program Nested = compile_string (#" +  inherit Live; +  string id = \"nested[0]\"; +  void create() {} +  void check_live_0 (mapping(object:int) checked) {check_live (checked);} +  class Nested1 +  { +  inherit Live; +  string id = \"nested[1]\"; +  void create() {} +  void check_live (mapping(object:int) checked) { +  checked[this_object()] = 1; +  if (catch (check_live_0 (checked))) +  my_error (\"Parent for %s got destructed too early.\\n\", id); +  else ::check_live (checked); +  } +  void check_live_1 (mapping(object:int) checked) {check_live (checked);} +  class Nested2 +  { +  inherit Live; +  string id = \"nested[2]\"; +  void create() {} +  void check_live (mapping(object:int) checked) { +  checked[this_object()] = 1; +  if (catch (check_live_1 (checked))) +  my_error (\"Parent for %s got destructed too early.\\n\", id); +  else ::check_live (checked); +  } +  } +  class Nested3 +  { +  inherit Live; +  string id = \"nested[3]\"; +  void create() {} +  void check_live (mapping(object:int) checked) { +  checked[this_object()] = 1; +  if (catch (check_live_1 (checked))) +  my_error (\"Parent for %s got destructed too early.\\n\", id); +  else ::check_live (checked); +  } +  } +  } +  "); +  add_constant ("destructing"); +  add_constant ("my_error"); +  add_constant ("Dead"); +  add_constant ("Live"); +  +  array(object) live, dead, nested; +  array(array) destruct_order_tests = ({ +  ({3, // Wanted number of live objects. +  0, // Wanted number of dead objects. +  0, // Wanted nested objects. +  lambda() { // Function to connect them. +  live[0]->x = live[1], live[0]->a = live[2]; +  live[1]->x = live[0]; +  }}), +  ({2, 2, 0, lambda() { // 1 +  live[0]->x = live[1], live[0]->a = dead[0]; +  live[1]->x = live[0]; +  dead[0]->a = dead[1]; +  dead[1]->a = dead[0]; +  }}), +  ({1, 2, 0, lambda() { // 2 +  live[0]->a = live[0], live[0]->b = dead[0]; +  dead[0]->a = dead[1]; +  dead[1]->a = dead[0]; +  }}), +  ({0, 3, 0, lambda() { // 3 +  dead[0]->a = dead[1]; +  dead[1]->a = dead[0]; +  dead[2]->a = dead[0], dead[2]->b = dead[2]; +  }}), +  ({3, 0, 0, lambda() { // 4 +  live[0]->a = live[0], live[0]->b = live[1]; +  live[1]->a = live[2]; +  }}), +  ({1, 2, 0, lambda() { // 5 +  live[0]->a = live[0], live[0]->b = dead[0]; +  dead[0]->a = dead[1]; +  }}), +  ({1, 2, 0, lambda() { // 6 +  live[0]->a = live[0], live[0]->b = dead[1]; +  dead[0]->a = dead[0], dead[0]->b = dead[1]; +  dead[1]->a = dead[1]; +  }}), +  ({2, 2, 0, lambda() { // 7 +  live[0]->a = live[0], live[0]->b = live[1]; +  dead[0]->a = dead[0]; +  dead[0]->b = live[1]; +  live[1]->a = dead[1]; +  dead[1]->a = dead[1]; +  }}), +  ({1, 3, 0, lambda() { // 8 +  live[0]->a = live[0], live[0]->b = dead[2]; +  dead[0]->a = dead[0]; +  dead[0]->b = dead[2]; +  dead[2]->a = dead[1]; +  dead[1]->a = dead[1]; +  }}), +  ({3, 1, 0, lambda() { // 9 +  live[0]->a = live[0], live[0]->b = live[1]; +  dead[0]->a = dead[0], dead[0]->b = live[1]; +  live[1]->a = live[2]; +  }}), +  ({1, 3, 0, lambda() { // 10 +  live[0]->a = live[0], live[0]->b = dead[1]; +  dead[0]->a = dead[0], dead[0]->b = dead[1]; +  dead[1]->a = dead[2]; +  }}), +  ({1, 3, 0, lambda() { // 11 +  live[0]->a = live[0], live[0]->b = dead[1]; +  dead[0]->a = dead[0], dead[0]->b = dead[1]; +  dead[1]->a = dead[1], dead[1]->b = dead[2]; +  dead[2]->a = dead[2]; +  }}), +  ({5, 0, 0, lambda() { // 12 +  live[0]->x = live[1]; +  live[1]->x = live[0], live[1]->a = live[2]; +  live[2]->x = live[3]; +  live[3]->x = live[2], live[3]->a = live[4]; +  live[4]->a = live[4]; +  }}), +  ({3, 0, 0, lambda() { // 13 +  live[0]->x = live[1], live[0]->y = live[2]; +  live[1]->x = live[2]; +  live[2]->x = live[0]; +  }}), +  ({2, 0, 0, lambda() { // 14 +  live[0]->a = live[1], live[0]->b = live[0]; +  live[1]->w[0] = live[0]; +  }}), +  ({2, 0, 0, lambda() { // 15 +  live[0]->a = live[0], live[0]->b = live[1]; +  live[1]->w[0] = live[0]; +  }}), +  ({2, 0, 0, lambda() { // 16 +  live[0]->a = live[0], live[0]->w[0] = live[1]; +  live[1]->x = live[0]; +  }}), +  ({3, 0, 0, lambda() { // 17 +  live[0]->a = live[0], live[0]->b = live[1]; +  live[1]->w[0] = live[2]; +  live[2]->a = live[2], live[2]->b = live[1]; +  }}), +  ({3, 0, 0, lambda() { // 18 +  live[0]->a = live[1], live[0]->x = live[2]; +  live[1]->w[0] = live[2]; +  live[2]->x = live[0]; +  }}), +  ({4, 0, 0, lambda() { // 19 +  live[0]->x = live[0], live[0]->a = live[1], live[0]->b = live[2]; +  live[1]->a = live[3]; +  live[2]->a = live[3]; +  live[3]->w[0] = live[0]; +  }}), +  ({3, 0, 0, lambda() { // 20 +  live[0]->x = live[1]; +  live[1]->x = live[0], live[1]->a = live[2]; +  live[2]->w[0] = live[1]; +  }}), +  ({4, 0, 0, lambda() { // 21 +  live[0]->w[0] = live[1], live[0]->a = live[3]; +  live[1]->w[0] = live[2]; +  live[2]->a = live[0], live[2]->b = live[3], live[2]->x = live[2]; +  live[3]->a = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 22 +  live[0]->a = dead[0], live[0]->x = live[1]; +  live[1]->x = live[0]; +  dead[0]->w[0] = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 23 +  live[0]->a = live[1], live[0]->b = dead[0]; +  live[1]->w[0] = dead[0]; +  dead[0]->x = live[0]; +  }}), +  ({3, 0, 0, lambda() { // 24 +  live[0]->x = live[0], live[0]->a = live[1], live[0]->b = live[2]; +  live[1]->w[0] = live[0], live[1]->w[1] = live[2]; +  live[2]->a = live[1]; +  }}), +  ({3, 0, 0, lambda() { // 25 +  live[0]->a = live[1]; +  live[1]->w[0] = live[2]; +  live[2]->x = live[2], live[2]->a = live[0], live[2]->b = live[1]; +  }}), +  ({3, 0, 0, lambda() { // 26 +  live[0]->w[0] = live[1], live[0]->a = live[2]; +  live[1]->x = live[1], live[1]->a = live[0], live[1]->b = live[2]; +  live[2]->w[0] = live[1]; +  }}), +  ({3, 0, 0, lambda() { // 27 +  live[0]->w[0] = live[1]; +  live[1]->x = live[1], live[1]->a = live[0], live[1]->b = live[2]; +  live[2]->a = live[0]; +  }}), +  ({3, 0, 0, lambda() { // 28 +  live[0]->a = live[0], live[0]->v[0] = live[1]; +  live[1]->a = live[1], live[1]->v[0] = live[2]; +  live[2]->a = live[2]; +  }}), +  ({2, 2, 0, lambda() { // 29 +  live[0]->x = live[1], live[0]->v[0] = dead[0]; +  live[1]->x = live[0]; +  dead[0]->a = dead[1]; +  dead[1]->a = dead[0]; +  }}), +  ({4, 0, 0, lambda() { // 30 +  live[0]->a = live[1], live[0]->b = live[2], live[0]->v[0] = live[3]; +  live[1]->w[0] = live[0]; +  live[2]->a = live[3]; +  live[3]->w[0] = live[2]; +  }}), +  ({2, 1, 0, lambda() { // 31 +  live[0]->a = dead[0]; +  dead[0]->a = live[0], dead[0]->b = live[1]; +  live[1]->a = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 32 +  live[0]->a = live[0], live[0]->b = dead[0]; +  live[1]->a = dead[0]; +  dead[0]->a = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 33 +  dead[0]->a = live[0]; +  live[0]->a = dead[0], live[0]->b = live[1]; +  live[1]->a = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 34 +  live[0]->a = dead[0]; +  dead[0]->b = live[0], dead[0]->a = live[1]; +  live[1]->a = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 35 +  live[0]->b = live[0], live[0]->a = dead[0]; +  live[1]->a = dead[0]; +  dead[0]->a = live[1]; +  }}), +  ({2, 1, 0, lambda() { // 36 +  dead[0]->a = live[0]; +  live[0]->b = dead[0], live[0]->a = live[1]; +  live[1]->a = live[1]; +  }}), +  ({3, 0, 0, lambda() { // 37 +  live[0]->a = live[0], live[0]->v[0] = live[1]; +  live[0]->checkfn = lambda (object o) { +  return o->v[0]->w[0]; +  }; +  live[1]->w[0] = live[2]; +  live[2]->a = live[1], live[2]->b = live[2]; +  }}), +  ({4, 0, 0, lambda() { // 38 +  live[0]->x = live[1]; +  live[1]->x = live[2]; +  live[2]->x = live[0], live[2]->w[0] = live[3]; +  live[3]->a = live[1], live[3]->b = live[3]; +  }}), +  ({0, 2, 2, lambda() { // 39 +  dead[0]->x = dead[0], dead[0]->a = nested[0]; +  dead[1]->x = dead[1], dead[1]->a = nested[1]; +  nested[0]->x = nested[1]; +  }}), +  ({0, 2, 2, lambda() { // 40 +  dead[0]->x = dead[0], dead[0]->a = nested[0]; +  dead[1]->x = dead[1], dead[1]->a = nested[1]; +  nested[0]->w[0] = nested[1]; +  }}), +  ({3, 0, 3, lambda() { // 41 +  live[0]->x = live[0], live[0]->a = nested[0]; +  live[1]->x = live[1], live[1]->a = nested[2]; +  live[2]->x = live[2], live[2]->a = nested[1]; +  nested[0]->x = nested[2]; +  }}), +  ({4, 0, 4, lambda() { // 42 +  live[0]->x = live[0], live[0]->a = nested[0]; +  live[1]->x = live[1], live[1]->a = nested[1]; +  live[2]->x = live[2], live[2]->a = nested[2]; +  live[3]->x = live[3], live[3]->a = nested[3]; +  nested[0]->x = nested[3]; +  }}), +  ({3, 0, 2, lambda() { // 43 +  live[0]->x = live[0], live[0]->a = nested[0]; +  live[1]->x = live[1], live[1]->a = nested[1]; +  nested[0]->a = live[2]; +  live[2]->x = nested[1]; +  }}), +  ({3, 0, 3, lambda() { // 44 +  live[0]->x = live[0], live[0]->a = nested[0]; +  live[1]->x = live[1], live[1]->a = nested[2]; +  live[2]->x = live[2], live[2]->a = nested[1]; +  nested[0]->x = nested[2]; +  nested[1]->a = live[0]; +  }}), + // ({3, 0, 0, lambda() { // Not possible without weak refs directly in objects. + // live[0]->x = live[0], live[0]->v[0] = live[1]; + // live[1]->x = live[1], live[1]->w[0] = live[2]; + // live[2]->x = live[2], live[2]->a = live[0]; + // }}), +  }); +  +  int test_failed = 0; +  for (int test = 0; test < sizeof (destruct_order_tests); test++) { +  [int nlive, int ndead, int nnested, function(void:void) setup] = +  destruct_order_tests[test]; +  int objs = nlive + ndead; +  array(int) idx = indices (allocate (objs)); +  int n = 1; +  for (int f = nlive + ndead; f > 1; f--) n *= f; +  werror ("GC destruct order test %d, %d permutations \r", test, n); +  while (n--) { +  array(int) alloc_order = Array.permute (idx, n); +  array(int) create_order = ({}); +  live = allocate (nlive); +  dead = allocate (ndead); +  if (nnested >= 1) { +  // Creating these before the Dead and Live objects below assumes +  // that the gc will start with the last created object first, so +  // the order can be controlled with those objects. +  nested = ({Nested()}); +  if (nnested >= 2) nested += ({nested[0]->Nested1()}); +  if (nnested >= 3) nested += ({nested[1]->Nested2()}); +  if (nnested >= 4) nested += ({nested[1]->Nested3()}); +  } +  for (int i = 0; i < objs; i++) { +  int p = alloc_order[i]; +  if (p < nlive) live[p] = Live (p), create_order += ({p}); +  else p -= nlive, dead[p] = Dead (p), create_order += ({-p - 1}); +  } +  destruct_order = ({""}); // Using ({}) would alloc a new array in destructing(). +  setup(); +  live = dead = nested = 0; +  int garbed = gc() + gc(); // Second gc to garb live object leftovers. +  destruct_order = destruct_order[1..]; +  if (!got_error && (got_error = sizeof (destruct_order) != nlive + nnested)) +  werror ("\nGC should garb %d live objects, " +  "but took %d.\n", nlive + nnested, sizeof (destruct_order)); +  if (!got_error && (got_error = garbed < 3 * (objs + nnested))) +  werror ("\nGC should garb at least %d things, " +  "but took only %d.\n", 3 * (objs + nnested), garbed); +  if (got_error) { +  werror ("Create order was: " + +  map (create_order, lambda (int i) { +  if (i < 0) return "dead[" + (-i - 1) + "]"; +  else return "live[" + i + "]"; +  }) * ", " + "\n" +  "Destruct order was: " + destruct_order * ", " + "\n"); +  test_failed = 1; +  got_error = 0; +  error(""); +  break; +  } +  } +  } +  werror ("%60s\r", ""); +  if (test_failed) error ("GC destruct order test failed.\n"); +  }]])   ]])      cond([[ sizeof( cpp("__AUTO_BIGNUM__")/"__AUTO_BIGNUM__" ) == 1 ]],