Changeset 2029
- Timestamp:
- 02/25/08 21:15:06 (3 months ago)
- Files:
-
- libswish3/trunk/bindings/perl/3.xs (modified) (9 diffs)
- libswish3/trunk/bindings/perl/XS/Analyzer.xs (modified) (2 diffs)
- libswish3/trunk/bindings/perl/XS/Config.xs (modified) (2 diffs)
- libswish3/trunk/bindings/perl/XS/Data.xs (modified) (1 diff)
- libswish3/trunk/bindings/perl/XS/Stash.xs (added)
- libswish3/trunk/bindings/perl/lib/SWISH/3.pm (modified) (2 diffs)
- libswish3/trunk/bindings/perl/macros.h (modified) (1 diff)
- libswish3/trunk/bindings/perl/t/07-refcnt.t (modified) (1 diff)
- libswish3/trunk/bindings/perl/t/08-handler.t (modified) (1 diff)
- libswish3/trunk/bindings/perl/t/10tokenize.t (modified) (1 diff)
- libswish3/trunk/bindings/perl/t/11get_set_parser.t (modified) (1 diff)
- libswish3/trunk/bindings/perl/t/12-stash.t (added)
- libswish3/trunk/bindings/perl/xs_helpers.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
libswish3/trunk/bindings/perl/3.xs
r2028 r2029 23 23 24 24 PREINIT: 25 HV* stash;26 HV* analyzer_stash;27 25 swish_3* s3; 28 26 29 27 CODE: 30 stash = newHV(); 31 s3 = swish_init_swish3( &sp_handler, newRV_inc((SV*)stash) ); 28 s3 = swish_init_swish3( &sp_handler, NULL ); 32 29 s3->ref_cnt++; 33 34 sp_hv_store(stash, DATA_CLASS_KEY, newSVpv(DATA_CLASS, 0)); 35 sp_hv_store(stash, CONFIG_CLASS_KEY, newSVpv(CONFIG_CLASS, 0)); 36 sp_hv_store(stash, ANALYZER_CLASS_KEY, newSVpv(ANALYZER_CLASS, 0)); 37 sp_hv_store(stash, PARSER_CLASS_KEY, newSVpv(PARSER_CLASS, 0)); 38 39 //sp_describe_object(s3->stash); 40 //sp_describe_object(newRV_noinc((SV*)s3->stash)); 30 s3->stash = sp_Stash_new(); 31 32 sp_Stash_set_char( s3->stash, DATA_CLASS_KEY, DATA_CLASS ); 33 sp_Stash_set_char( s3->stash, CONFIG_CLASS_KEY, CONFIG_CLASS ); 34 sp_Stash_set_char( s3->stash, ANALYZER_CLASS_KEY, ANALYZER_CLASS ); 35 sp_Stash_set_char( s3->stash, PARSER_CLASS_KEY, PARSER_CLASS ); 36 sp_Stash_set_char( s3->stash, SELF_CLASS_KEY, CLASS ); 37 38 //warn("new() stash refcnt = %d\n", SvREFCNT((SV*)SvRV((SV*)s3->stash))); 39 40 //sp_describe_object( (SV*)s3->stash ); 41 41 42 42 s3->analyzer->tokenizer = &sp_tokenize; 43 analyzer_stash = newHV(); 44 s3->analyzer->stash = newRV_inc((SV*)analyzer_stash); 43 s3->analyzer->stash = sp_Stash_new(); 44 sp_Stash_set_char( s3->analyzer->stash, SELF_CLASS_KEY, ANALYZER_CLASS ); 45 s3->config->stash = sp_Stash_new(); 46 sp_Stash_set_char( s3->config->stash, SELF_CLASS_KEY, CONFIG_CLASS ); 45 47 46 48 RETVAL = s3; … … 148 150 set_analyzer_class = 15 149 151 get_analyzer_class = 16 150 set_stash = 17 151 get_stash = 18 152 set_regex = 19 153 get_regex = 20 152 set_regex = 17 153 get_regex = 18 154 154 PREINIT: 155 SV* stash; 156 SV* RETVAL; 157 SV* tmp; 155 SV *RETVAL; 156 char *class; 158 157 PPCODE: 159 158 { 160 161 stash = self->stash;162 // TODO need this?163 SvREFCNT_inc(stash);164 159 165 160 //warn("number of items %d for ix %d", items, ix); … … 174 169 warn("freeing config on set_config"); 175 170 } 171 sp_Stash_destroy(self->config->stash); 172 if (self->config->stash != NULL) { 173 //SWISH_WARN("set config stash to NULL"); 174 self->config->stash = NULL; 175 } 176 176 swish_free_config(self->config); 177 177 } … … 183 183 // get_config 184 184 case 2: self->config->ref_cnt++; 185 RETVAL = sp_bless_ptr(sp_hvref_fetch_as_char(stash, CONFIG_CLASS_KEY), (IV)self->config); 185 class = sp_Stash_get_char(self->stash, CONFIG_CLASS_KEY); 186 sp_Stash_set_char( self->config->stash, SELF_CLASS_KEY, class ); 187 RETVAL = sp_bless_ptr(class, (IV)self->config); 186 188 break; 187 189 … … 193 195 warn("freeing analyzer on set_analyzer"); 194 196 } 197 sp_Stash_destroy(self->analyzer->stash); 195 198 swish_free_analyzer(self->analyzer); 196 199 } … … 202 205 // get_analyzer 203 206 case 4: self->analyzer->ref_cnt++; 204 RETVAL = sp_bless_ptr(sp_hvref_fetch_as_char(stash, ANALYZER_CLASS_KEY), (IV)self->analyzer); 207 class = sp_Stash_get_char(self->stash, ANALYZER_CLASS_KEY); 208 sp_Stash_set_char( self->analyzer->stash, SELF_CLASS_KEY, class ); 209 RETVAL = sp_bless_ptr(class, (IV)self->analyzer); 205 210 break; 206 211 … … 219 224 // get_parser 220 225 case 6: self->parser->ref_cnt++; 221 RETVAL = sp_bless_ptr(sp_hvref_fetch_as_char(stash, PARSER_CLASS_KEY), (IV)self->parser); 226 class = sp_Stash_get_char(self->stash, PARSER_CLASS_KEY); 227 RETVAL = sp_bless_ptr(class, (IV)self->parser); 222 228 break; 223 229 224 230 // set_handler 225 case 7: sp_ hvref_replace(stash, HANDLER_KEY, ST(1));231 case 7: sp_Stash_replace(self->stash, HANDLER_KEY, ST(1)); 226 232 break; 227 233 228 234 // get_handler 229 case 8: RETVAL = sp_ hvref_fetch(stash, HANDLER_KEY);235 case 8: RETVAL = sp_Stash_get(self->stash, HANDLER_KEY); 230 236 break; 231 237 232 238 // set_data_class 233 case 9: sp_ hvref_replace(stash, DATA_CLASS_KEY, ST(1));239 case 9: sp_Stash_replace(self->stash, DATA_CLASS_KEY, ST(1)); 234 240 break; 235 241 236 242 // get_data_class 237 case 10: RETVAL = sp_ hvref_fetch(stash, DATA_CLASS_KEY);243 case 10: RETVAL = sp_Stash_get(self->stash, DATA_CLASS_KEY); 238 244 break; 239 245 240 246 // set_parser_class 241 case 11: sp_ hvref_replace(stash, PARSER_CLASS_KEY, ST(1));247 case 11: sp_Stash_replace(self->stash, PARSER_CLASS_KEY, ST(1)); 242 248 break; 243 249 244 250 // get_parser_class 245 case 12: RETVAL = sp_ hvref_fetch(stash, PARSER_CLASS_KEY);251 case 12: RETVAL = sp_Stash_get(self->stash, PARSER_CLASS_KEY); 246 252 break; 247 253 248 254 // set_config_class 249 case 13: sp_ hvref_replace(stash, CONFIG_CLASS_KEY, ST(1));255 case 13: sp_Stash_replace(self->stash, CONFIG_CLASS_KEY, ST(1)); 250 256 break; 251 257 252 258 // get_config_class 253 case 14: RETVAL = sp_ hvref_fetch(stash, CONFIG_CLASS_KEY);259 case 14: RETVAL = sp_Stash_get(self->stash, CONFIG_CLASS_KEY); 254 260 break; 255 261 256 262 // set_analyzer_class 257 case 15: sp_ hvref_replace(stash, ANALYZER_CLASS_KEY, ST(1));263 case 15: sp_Stash_replace(self->stash, ANALYZER_CLASS_KEY, ST(1)); 258 264 break; 259 265 260 266 // get_analyzer_class 261 case 16: RETVAL = sp_hvref_fetch(stash, ANALYZER_CLASS_KEY); 262 break; 263 264 // set_stash 265 case 17: self->stash = ST(1); 266 break; 267 268 // get_stash 269 case 18: RETVAL = stash; 270 SvREFCNT_inc( self->stash ); 267 case 16: RETVAL = sp_Stash_get(self->stash, ANALYZER_CLASS_KEY); 271 268 break; 272 269 273 270 // set_regex 274 case 1 9: sp_SV_is_qr( ST(1) );271 case 17: sp_SV_is_qr( ST(1) ); 275 272 self->analyzer->regex = SvREFCNT_inc( ST(1) ); 276 273 break; 277 274 278 275 // get_regex 279 case 20: RETVAL = self->analyzer->regex;276 case 18: RETVAL = self->analyzer->regex; 280 277 break; 281 278 … … 293 290 s3 = (swish_3*)sp_extract_ptr(self); 294 291 s3->ref_cnt--; 292 293 if ( SWISH_DEBUG ) { 294 warn("s3->stash refcnt = %d\n", 295 sp_Stash_inner_refcnt(s3->stash) ); 296 warn("s3->config->stash refcnt = %d\n", 297 sp_Stash_inner_refcnt( s3->config->stash) ); 298 warn("s3->analyzer->stash refcnt = %d\n", 299 sp_Stash_inner_refcnt( s3->analyzer->stash) ); 300 301 } 295 302 296 303 if (SWISH_DEBUG) { 297 304 warn("DESTROYing swish_3 object %s [%d] [ref_cnt = %d]", 298 SvPV(ST(0), PL_na), s elf, s3->ref_cnt);305 SvPV(ST(0), PL_na), s3, s3->ref_cnt); 299 306 } 300 307 301 308 if (s3->ref_cnt < 1) { 309 sp_Stash_destroy( s3->stash ); 310 if ( s3->config->ref_cnt == 1 ) { 311 sp_Stash_destroy( s3->config->stash ); 312 //SWISH_WARN("set config stash to NULL"); 313 s3->config->stash = NULL; 314 } 315 if ( s3->analyzer->ref_cnt == 1 ) { 316 sp_Stash_destroy( s3->analyzer->stash ); 317 } 318 302 319 swish_free_swish3( s3 ); 303 320 } … … 324 341 INCLUDE: XS/Doc.xs 325 342 INCLUDE: XS/Data.xs 326 343 INCLUDE: XS/Stash.xs 344 libswish3/trunk/bindings/perl/XS/Analyzer.xs
r2028 r2029 63 63 CODE: 64 64 self->ref_cnt--; 65 65 66 66 if (SWISH_DEBUG) { 67 67 warn("DESTROYing swish_Analyzer object %s [%d] [ref_cnt = %d]", … … 70 70 71 71 if (self->ref_cnt < 1) { 72 sp_Stash_destroy( self->stash ); 72 73 swish_free_analyzer(self); 73 74 } libswish3/trunk/bindings/perl/XS/Config.xs
r2028 r2029 109 109 void 110 110 DESTROY(self) 111 swish_Config* self 111 swish_Config* self; 112 112 113 113 CODE: 114 114 self->ref_cnt--; 115 116 if (self->stash != NULL) { 117 SvREFCNT_dec(self->stash); 118 } 119 115 120 116 if (SWISH_DEBUG) { 121 117 warn("DESTROYing swish_Config object %s [%d] [ref_cnt = %d]", … … 125 121 if (self->ref_cnt < 1) { 126 122 127 if (self->stash != NULL) { 128 if (SWISH_DEBUG) { 129 warn("decreasing refcnt on config->stash [currently %d]", 130 SvREFCNT((SV*)SvRV((SV*)self->stash)) 131 ); 132 } 133 while ( SvREFCNT((SV*)SvRV((SV*)self->stash)) > 0 ) { 134 SvREFCNT_dec(self->stash); 135 } 136 self->stash = NULL; 137 } 138 123 sp_Stash_destroy( self->stash ); 124 //SWISH_WARN("set config stash to NULL"); 125 self->stash = NULL; 139 126 swish_free_config( self ); 140 127 libswish3/trunk/bindings/perl/XS/Data.xs
r2028 r2029 14 14 CODE: 15 15 self->s3->ref_cnt++; 16 class = sp_hvref_fetch_as_char((SV*)self->s3->stash, S WISH3_CLASS_KEY);16 class = sp_hvref_fetch_as_char((SV*)self->s3->stash, SELF_CLASS_KEY); 17 17 warn("s3 class = %s\n", class); 18 18 RETVAL = sp_bless_ptr( class, (IV)self->s3 ); libswish3/trunk/bindings/perl/lib/SWISH/3.pm
r2028 r2029 56 56 } 57 57 58 # defaults58 # override defaults 59 59 for my $param (qw( data_class parser_class config_class analyzer_class )) 60 60 { 61 61 my $method = 'set_' . $param; 62 62 63 #warn "$method"; 64 $self->$method( $arg{$param} ) if exists $arg{param}; 63 if ( exists $arg{$param} ) { 64 65 #warn "$method"; 66 $self->$method( $arg{$param} ); 67 } 65 68 } 66 69 … … 105 108 sub default_handler { 106 109 my $data = shift; 110 unless ( $ENV{SWISH_DEBUG} ) { 111 warn "default handler called\n"; 112 return; 113 } 107 114 108 115 select(STDERR); libswish3/trunk/bindings/perl/macros.h
r2028 r2029 21 21 #define PARSER_KEY "sp_parser" 22 22 #define TOKEN_HANDLER_KEY "sp_token_handler" 23 #define S WISH3_CLASS_KEY"sp_self_class"23 #define SELF_CLASS_KEY "sp_self_class" 24 24 25 25 libswish3/trunk/bindings/perl/t/07-refcnt.t
r2028 r2029 21 21 # avoid spurious mem error from libswish3 22 22 # just because of order of Perl ref cleanup 23 undef $analyzer;23 #undef $analyzer; 24 24 libswish3/trunk/bindings/perl/t/08-handler.t
r2028 r2029 3 3 use_ok('SWISH::3'); 4 4 5 ok( my $s3 = SWISH::3->new( handler => sub { diag("got data: $_[0] ") } ),6 #ok( my $s3 = SWISH::3->new( ),5 #ok( my $s3 = SWISH::3->new( handler => sub { diag("got data: $_[0] ") } ), 6 ok( my $s3 = SWISH::3->new( ), 7 7 "new parser" ); 8 8 ok( $s3->parse("t/test.html"), "parse HTML" ); libswish3/trunk/bindings/perl/t/10tokenize.t
r2028 r2029 36 36 } 37 37 38 undef $analyzer;39 undef $wlist;40 undef $s3;38 #undef $analyzer; 39 #undef $wlist; 40 #undef $s3; libswish3/trunk/bindings/perl/t/11get_set_parser.t
r2028 r2029 38 38 # avoid spurious libswish3 mem error due to "random" order of Perl 39 39 # SV cleanup 40 undef $analyzer;41 undef $ana2;42 undef $ana1;43 undef $conf2;44 undef $conf1;45 undef $config;46 undef $s3;40 #undef $analyzer; 41 #undef $ana2; 42 #undef $ana1; 43 #undef $conf2; 44 #undef $conf1; 45 #undef $config; 46 #undef $s3; 47 47 libswish3/trunk/bindings/perl/xs_helpers.c
r2028 r2029 6 6 /* C code to make writing XS easier */ 7 7 8 /* sp_Obj is a struct that makes refcounting easier */ 9 10 typedef struct sp_Obj sp_Obj; 11 struct sp_Obj 12 { 13 void *c_ptr; 14 SV *perl_obj; 15 }; 16 17 static SV* sp_hv_store( HV* h, const char* key, SV* val); 18 static SV* sp_hvref_store( SV* h, const char* key, SV* val); 8 static SV* sp_hv_store( HV* h, const char* key, SV* val ); 9 static SV* sp_hv_store_char( HV* h, const char* key, char *val ); 10 static SV* sp_hvref_store( SV* h, const char* key, SV* val ); 11 static SV* sp_hvref_store_char( SV* h, const char* key, char *val ); 19 12 static SV* sp_hv_fetch( HV* h, const char* key ); 20 13 static SV* sp_hvref_fetch( SV* h, const char* key ); … … 25 18 static SV* sp_hv_delete( HV* h, const char* key ); 26 19 static SV* sp_hvref_delete( SV* h, const char* key ); 20 static void sp_hv_replace( HV *h, char* key, SV* value ); 27 21 static void sp_hvref_replace( SV * hashref, char* key, SV* value ); 28 22 static SV* sp_bless_ptr( char* CLASS, IV c_ptr ); 29 23 static char* sp_get_objects_class( SV* object ); 30 static HV* sp_extract_hash _from_object( SV* object );24 static HV* sp_extract_hash( SV* object ); 31 25 static void sp_dump_hash( SV* hash_ref ); 32 26 static void sp_describe_object( SV* object ); … … 49 43 static swish_Analyzer* sp_new_analyzer(); 50 44 51 static sp_Obj* sp_new_Obj( char* class, void* c_ptr); 52 static SV* sp_Obj_to_perl(sp_Obj* self); 53 static void sp_Obj_inc_refcount(sp_Obj *self); 54 static void sp_Obj_dec_refcount(sp_Obj *self); 55 static int sp_Obj_get_refcount(sp_Obj *self); 45 /* implements nearly all methods for SWISH::3::Stash, a private class */ 46 47 static SV* sp_Stash_new(); 48 static void sp_Stash_set( SV *object, const char *key, SV *value ); 49 static void sp_Stash_set_char( SV *object, const char *key, char *value ); 50 static SV* sp_Stash_get( SV *object, const char *key ); 51 static char* sp_Stash_get_char( SV *object, const char *key ); 52 static void sp_Stash_replace( SV *object, const char *key, SV *value ); 53 static int sp_Stash_inner_refcnt( SV *object ); 54 static void sp_Stash_destroy( SV *object ); 55 56 static SV* 57 sp_Stash_new() 58 { 59 HV *hash; 60 SV *object; 61 hash = newHV(); 62 object = sv_bless( newRV((SV*)hash), gv_stashpv("SWISH::3::Stash",0) ); 63 //SvREFCNT_dec( hash ); 64 return object; 65 } 66 67 static void 68 sp_Stash_set( SV *object, const char *key, SV *value ) 69 { 70 HV *hash; 71 hash = sp_extract_hash( object ); 72 sp_hv_store( hash, key, value ); 73 } 74 75 static void 76 sp_Stash_set_char( SV *object, const char *key, char *value ) 77 { 78 HV *hash; 79 hash = sp_extract_hash( object ); 80 sp_hv_store_char( hash, key, value ); 81 } 82 83 static SV* 84 sp_Stash_get( SV *object, const char *key ) 85 { 86 HV *hash; 87 hash = sp_extract_hash( object ); 88 //return SvREFCNT_inc( sp_hv_fetch( hash, key ) ); 89 return sp_hv_fetch( hash, key ); 90 } 91 92 static char* 93 sp_Stash_get_char( SV *object, const char *key ) 94 { 95 HV *hash; 96 hash = sp_extract_hash( object ); 97 return sp_hv_fetch_as_char( hash, key ); 98 } 99 100 static void 101 sp_Stash_replace( SV *object, const char *key, SV *value ) 102 { 103 HV *hash; 104 hash = sp_extract_hash( object ); 105 return sp_hv_replace( hash, (char*)key, value ); 106 } 56 107 57 108 static int 58 sp_Obj_get_refcount(sp_Obj *self) 59 { 60 return SvREFCNT(self->perl_obj); 61 } 62 63 static void 64 sp_Obj_inc_refcount(sp_Obj *self) 65 { 66 SvREFCNT_inc(self->perl_obj); 67 } 68 69 static void 70 sp_Obj_dec_refcount(sp_Obj *self) 71 { 72 /* If the SV's refcount falls to 0, DESTROY will be invoked from 73 * Perl-space. 74 */ 75 SvREFCNT_dec(self->perl_obj); 76 } 77 78 79 static sp_Obj* 80 sp_new_Obj( char *class, void *c_ptr ) 81 { 82 sp_Obj* self; 83 SV* perl_obj; 84 85 self = swish_xmalloc(sizeof(sp_Obj*)); 86 self->c_ptr = c_ptr; 87 88 /* init a new perl object wrapping the sp_Obj ptr */ 89 perl_obj = newSV(0); 90 sv_setref_pv(perl_obj, class, self); 91 92 /* make a reference to the object and save the reference */ 93 self->perl_obj = SvRV(perl_obj); 94 95 /* increment ref count of the inner object (perl_obj) */ 96 sp_Obj_inc_refcount(self); 97 98 /* decrement the outer object (RV) so that it is DESTROYed 99 by Perl when we return self 100 */ 101 SvREFCNT_dec(perl_obj); 102 103 /* self contains the original c_ptr and a perl SV 104 which is a wrapper around self. This means we use Perl's 105 reference counting feature to control when our sp_Obj ptr 106 is DESTROYed. 107 */ 108 109 return self; 110 } 111 112 static SV* 113 sp_Obj_to_perl( sp_Obj* self ) 114 { 115 return newRV_inc(self->perl_obj); 116 } 109 sp_Stash_inner_refcnt( SV *object ) 110 { 111 return SvREFCNT((SV*)SvRV((SV*)object)); 112 } 113 114 static void 115 sp_Stash_destroy( SV *object ) 116 { 117 HV *hash; 118 hash = sp_extract_hash( object ); 119 if ( SWISH_DEBUG ) { 120 warn("Stash_destroy Stash object %s for class %s [%d]", 121 SvPV(object, PL_na), sp_hv_fetch_as_char(hash, SELF_CLASS_KEY), object); 122 warn("Stash object refcnt = %d", SvREFCNT(object)); 123 warn("Stash hash refcnt = %d", SvREFCNT(hash)); 124 } 125 hv_undef(hash); 126 //sp_describe_object( object ); 127 if (SvREFCNT( hash )) { 128 SvREFCNT_dec( hash ); 129 } 130 if (SvREFCNT( object ) ) { 131 SvREFCNT_dec( object ); 132 } 133 } 134 117 135 118 136 static void … … 149 167 return *ok; 150 168 } 169 170 static SV* 171 sp_hv_store_char( HV* h, const char *key, char *val) 172 { 173 dTHX; 174 SV *value; 175 value = newSVpv(val, 0); 176 sp_hv_store( h, key, value ); 177 SvREFCNT_dec(value); 178 return value; 179 } 180 151 181 static SV* 152 182 sp_hvref_store( SV* h, const char* key, SV* val) 153 183 { 154 184 return sp_hv_store( (HV*)SvRV(h), key, val ); 185 } 186 187 static SV* 188 sp_hvref_store_char( SV* h, const char* key, char *val) 189 { 190 return sp_hv_store_char( (HV*)SvRV(h), key, val ); 155 191 } 156 192 … … 258 294 dTHX; 259 295 char* class = sv_reftype(SvRV(object), 1); 260 warn("object belongs to %s\n", class);296 //warn("object belongs to %s\n", class); 261 297 return class; 262 298 } 263 299 264 300 static HV* 265 sp_extract_hash_from_object( SV* object ) 266 { 267 dTHX; 268 HV* hash = NULL; 269 char* class = sp_get_objects_class( object ); 301 sp_extract_hash( SV* object ) 302 { 303 dTHX; 304 HV* hash; 305 char* class; 306 307 class = sp_get_objects_class( object ); 270 308 if (SvROK(object) && SvTYPE(SvRV(object))==SVt_PVHV) 271 309 hash = (HV*)SvRV(object); … … 355 393 char* class = sp_get_objects_class( object ); 356 394 //warn("looking for %s in %s\n", name, class); 357 HV* hash = sp_extract_hash _from_object( object );395 HV* hash = sp_extract_hash( object ); 358 396 SV* sv = sp_hv_fetch( hash, (const char*)name ); 359 397 … … 362 400 363 401 return sv; 402 } 403 404 static void 405 sp_hv_replace( HV *hash, char *key, SV *value ) 406 { 407 if (sp_hv_exists(hash, key)) { 408 sp_hv_delete(hash, key); 409 } 410 sp_hv_store( hash, key, value ); 364 411 } 365 412 … … 720 767 config = swish_init_config(); 721 768 config->ref_cnt++; 722 //config->stash = newRV_inc((SV*)stash); 723 //sp_hvref_store( config->stash, SELF_KEY, sp_bless_ptr(CONFIG_CLASS, (IV)config) ); 769 config->stash = sp_Stash_new(); 724 770 725 771 return config;
