merge
[tamarin-stm.git] / extensions / ST_mmgc_575631.st
blobb47272c08d0728b2dee61791713ed38c7a7ef755
1 // -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*-
2 // vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5)
3 //
4 // ***** BEGIN LICENSE BLOCK *****
5 // Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 //
7 // The contents of this file are subject to the Mozilla Public License Version
8 // 1.1 (the "License"); you may not use this file except in compliance with
9 // the License. You may obtain a copy of the License at
10 // http://www.mozilla.org/MPL/
12 // Software distributed under the License is distributed on an "AS IS" basis,
13 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 // for the specific language governing rights and limitations under the
15 // License.
17 // The Original Code is [Open Source Virtual Machine.].
19 // The Initial Developer of the Original Code is
20 // Adobe System Incorporated.
21 // Portions created by the Initial Developer are Copyright (C) 2004-2006
22 // the Initial Developer. All Rights Reserved.
24 // Contributor(s):
25 //   Adobe AS3 Team
27 // Alternatively, the contents of this file may be used under the terms of
28 // either the GNU General Public License Version 2 or later (the "GPL"), or
29 // the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 // in which case the provisions of the GPL or the LGPL are applicable instead
31 // of those above. If you wish to allow use of your version of this file only
32 // under the terms of either the GPL or the LGPL, and not to allow others to
33 // use your version of this file under the terms of the MPL, indicate your
34 // decision by deleting the provisions above and replace them with the notice
35 // and other provisions required by the GPL or the LGPL. If you do not delete
36 // the provisions above, a recipient may use your version of this file under
37 // the terms of any one of the MPL, the GPL or the LGPL.
39 // ***** END LICENSE BLOCK ***** */
41 // Bugzilla 565631 - We occasionally interleave invoking finalizers
42 // and clearing mark bits in GCAlloc::Finalize; so a finalizer can
43 // observe a live object that does not have its mark bit set.
45 // This complicates things because we want to ensure that unmarked
46 // weakly-referenced objects are resurrected by the GC if the weak
47 // reference is dereferenced during presweep, but we do not want to
48 // schedule collection work (or set bits that are supposed to be
49 // unmarked) during finalization.
51 // (Long term we might want to get rid of the interleaving of
52 // finalization and mark-bit clearing.  Short term, lets just
53 // try to detect this on our own.)
55 %%component mmgc
56 %%category bugzilla_575631
58 %%prefix
59 using namespace MMgc;
61 // Upon destruction, start reading weak refs of "friends" near and far
62 class Snoopy : public GCFinalizedObject
64 public:
65     Snoopy(int key, GCWeakRef** refs, int len)
66         : key(key), friends(refs), len(len)
67     {
68         ++alive_count;
69     }
70     ~Snoopy();
71     static int alive_count;
72 private:
73     int key;
74     GCWeakRef** friends;
75     int len;
78 // To take D samples from an array of N elems, walk thru by floor(N/D)
79 // steps (but avoid the pathological case when the floor is zero).
80 int compute_stride(int numerator, int denominator)
82     int delta = numerator / denominator;
83     return (delta > 0) ? delta : 1;
86 %%decls
87 // collecting twice is only "sure" way to gc in presence of incrementality
88 void collect2() { core->gc->Collect(); core->gc->Collect(); }
90 %%methods
92 /*static*/ int Snoopy::alive_count = 0;
94 const int arr_len = 1000;
95 const int lookups_per_destruct = 10;
96 const int destructs = 10;
97 Snoopy::~Snoopy()
99     int delta = compute_stride(arr_len, lookups_per_destruct);
101     for ( int i = 1 ; i < arr_len ; i += delta ) {
102         int idx = (key + i) % len;
103         // printf("referencing ref[%d] from Snoopy(%d)\n", idx, key);
104         friends[idx]->get();
105     }
106     --alive_count;
109 %%test drizzle
111     GC* gc = core->gc;
113     Snoopy* objs[arr_len];
114     GCWeakRef* refs[arr_len];
116     // initial setup:
117     for (int i=0 ; i < arr_len; ++i ) {
118         objs[i] = new (gc) Snoopy(i, refs, arr_len);
119         refs[i] = objs[i]->GetWeakRef();
120     }
122     collect2();
124     int delta = compute_stride(arr_len, destructs);
126     for (int i=0; i < arr_len; i += delta) {
127         objs[i] = NULL;
128         collect2();
129     }
131     // not assert failing within get() is passing the test.
132     %%verify 1
133           ; // (make my auto-indenter happy)
135     // cleanup code; letting ~Snoopy occur outside test extent is big no-no.
136     {
137         for (int i=0; i < arr_len; ++i ) {
138             if (! refs[i]->isNull())
139                 delete objs[i];
140         }
142         // if something went wrong above and some Snoopy's are still alive,
143         // we'll get burned during their destructors.  Make sure that
144         // does not happen.
145         %%verify (Snoopy::alive_count == 0)
146               ;
147     }