@@ -27,7 +27,6 @@ use cast::transmute;
27
27
use ops:: Drop ;
28
28
use cmp:: { Eq , Ord } ;
29
29
use clone:: { Clone , DeepClone } ;
30
- use rt:: global_heap:: exchange_free;
31
30
use ptr:: read_ptr;
32
31
use option:: { Option , Some , None } ;
33
32
@@ -57,30 +56,38 @@ impl<T> Rc<T> {
57
56
/// Borrow the value contained in the reference-counted box
58
57
#[ inline( always) ]
59
58
pub fn borrow < ' a > ( & ' a self ) -> & ' a T {
60
- unsafe { & ( * self . ptr ) . value }
59
+ & self . inner ( ) . value
61
60
}
62
61
63
62
/// Downgrade the reference-counted pointer to a weak reference
64
63
pub fn downgrade ( & self ) -> Weak < T > {
65
- unsafe {
66
- ( * self . ptr ) . weak += 1 ;
67
- Weak { ptr : self . ptr }
68
- }
64
+ self . inner ( ) . weak += 1 ;
65
+ Weak { ptr : self . ptr }
66
+ }
67
+
68
+ fn inner < ' a > ( & ' a self ) -> & ' a mut RcBox < T > {
69
+ // Note that we need the indrection of &~RcBox<T> because we can't
70
+ // transmute *RcBox to &RcBox (the actual pointer layout is different if
71
+ // T contains managed pointers at this time)
72
+ let ptr: & mut ~RcBox < T > = unsafe { transmute ( & self . ptr ) } ;
73
+ & mut * * ptr
69
74
}
70
75
}
71
76
72
77
#[ unsafe_destructor]
73
78
impl < T > Drop for Rc < T > {
74
79
fn drop ( & mut self ) {
75
- unsafe {
76
- if self . ptr != 0 as * mut RcBox < T > {
77
- ( * self . ptr ) . strong -= 1 ;
78
- if ( * self . ptr ) . strong == 0 {
79
- read_ptr ( self . borrow ( ) ) ; // destroy the contained object
80
- if ( * self . ptr ) . weak == 0 {
81
- exchange_free ( self . ptr as * mut u8 as * i8 )
82
- }
83
- }
80
+ if self . ptr == 0 as * mut RcBox < T > { return }
81
+
82
+ let inner = self . inner ( ) ;
83
+ inner. strong -= 1 ;
84
+ if inner. strong == 0 {
85
+ // If we've run out of strong pointers, we need to be sure to run
86
+ // the destructor *now*, but we can't free the value just yet (weak
87
+ // pointers may still be active).
88
+ unsafe { read_ptr ( & inner. value ) ; } // destroy the contained object
89
+ if inner. weak == 0 {
90
+ free ( self . ptr ) ;
84
91
}
85
92
}
86
93
}
@@ -89,10 +96,8 @@ impl<T> Drop for Rc<T> {
89
96
impl < T > Clone for Rc < T > {
90
97
#[ inline]
91
98
fn clone ( & self ) -> Rc < T > {
92
- unsafe {
93
- ( * self . ptr ) . strong += 1 ;
94
- Rc { ptr : self . ptr }
95
- }
99
+ self . inner ( ) . strong += 1 ;
100
+ Rc { ptr : self . ptr }
96
101
}
97
102
}
98
103
@@ -135,41 +140,56 @@ pub struct Weak<T> {
135
140
impl < T > Weak < T > {
136
141
/// Upgrade a weak reference to a strong reference
137
142
pub fn upgrade ( & self ) -> Option < Rc < T > > {
138
- unsafe {
139
- if ( * self . ptr ) . strong == 0 {
140
- None
141
- } else {
142
- ( * self . ptr ) . strong += 1 ;
143
- Some ( Rc { ptr : self . ptr } )
144
- }
143
+ if self . inner ( ) . strong == 0 {
144
+ None
145
+ } else {
146
+ self . inner ( ) . strong += 1 ;
147
+ Some ( Rc { ptr : self . ptr } )
145
148
}
146
149
}
150
+
151
+ fn inner < ' a > ( & ' a self ) -> & ' a mut RcBox < T > {
152
+ // see above version
153
+ let ptr: & mut ~RcBox < T > = unsafe { transmute ( & self . ptr ) } ;
154
+ & mut * * ptr
155
+ }
147
156
}
148
157
149
158
#[ unsafe_destructor]
150
159
impl < T > Drop for Weak < T > {
151
160
fn drop ( & mut self ) {
152
- unsafe {
153
- if self . ptr != 0 as * mut RcBox < T > {
154
- ( * self . ptr ) . weak -= 1 ;
155
- if ( * self . ptr ) . weak == 0 && ( * self . ptr ) . strong == 0 {
156
- exchange_free ( self . ptr as * mut u8 as * i8 )
157
- }
158
- }
161
+ if self . ptr as uint == 0 { return }
162
+
163
+ let inner = self . inner ( ) ;
164
+ inner. weak -= 1 ;
165
+ if inner. weak == 0 && inner. strong == 0 {
166
+ free ( self . ptr ) ;
159
167
}
160
168
}
161
169
}
162
170
163
171
impl < T > Clone for Weak < T > {
164
172
#[ inline]
165
173
fn clone ( & self ) -> Weak < T > {
166
- unsafe {
167
- ( * self . ptr ) . weak += 1 ;
168
- Weak { ptr : self . ptr }
169
- }
174
+ self . inner ( ) . weak += 1 ;
175
+ Weak { ptr : self . ptr }
170
176
}
171
177
}
172
178
179
+ // We need to be very careful when dropping this inner box pointer. We don't
180
+ // necessarily know the right free function to call because it's different
181
+ // depending on whether T contains managed pointers or not. The other sticky
182
+ // part is that we can't run the destructor for T because it's already been run.
183
+ //
184
+ // To get around this, we transmute the pointer to an owned pointer with a type
185
+ // that has size 0. This preserves the managed-ness of the type along with
186
+ // preventing any destructors from being run. Note that this assumes that the GC
187
+ // doesn't need to know the real size of the pointer (it's just malloc right
188
+ // now), so this works for now but may need to change in the future.
189
+ fn free < T > ( ptr : * mut RcBox < T > ) {
190
+ let _: ~RcBox < [ T , ..0 ] > = unsafe { transmute ( ptr) } ;
191
+ }
192
+
173
193
#[ cfg( test) ]
174
194
mod tests {
175
195
use prelude:: * ;
@@ -230,4 +250,12 @@ mod tests {
230
250
drop ( x) ;
231
251
assert ! ( y. upgrade( ) . is_none( ) ) ;
232
252
}
253
+
254
+ #[ test]
255
+ fn gc_inside ( ) {
256
+ // see issue #11532
257
+ use { cell, gc} ;
258
+ let a = Rc :: new ( cell:: RefCell :: new ( gc:: Gc :: new ( 1 ) ) ) ;
259
+ assert ! ( a. borrow( ) . try_borrow_mut( ) . is_some( ) ) ;
260
+ }
233
261
}
0 commit comments