]> git.vpit.fr Git - perl/modules/Lexical-Types.git/blob - Types.xs
Do not mix declarations and code
[perl/modules/Lexical-Types.git] / Types.xs
1 /* This file is part of the Lexical-Types Perl module.
2  * See http://search.cpan.org/dist/Lexical-Types/ */
3
4 #define PERL_NO_GET_CONTEXT
5 #include "EXTERN.h"
6 #include "perl.h"
7 #include "XSUB.h"
8
9 #define __PACKAGE__     "Lexical::Types"
10 #define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1)
11
12 /* --- Compatibility wrappers ---------------------------------------------- */
13
14 #define LT_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
15
16 #if LT_HAS_PERL(5, 10, 0) || defined(PL_parser)
17 # ifndef PL_in_my_stash
18 #  define PL_in_my_stash PL_parser->in_my_stash
19 # endif
20 #else
21 # ifndef PL_in_my_stash
22 #  define PL_in_my_stash PL_Iin_my_stash
23 # endif
24 #endif
25
26 #ifndef LT_WORKAROUND_REQUIRE_PROPAGATION
27 # define LT_WORKAROUND_REQUIRE_PROPAGATION !LT_HAS_PERL(5, 10, 1)
28 #endif
29
30 #ifndef HvNAME_get
31 # define HvNAME_get(H) HvNAME(H)
32 #endif
33
34 #ifndef HvNAMELEN_get
35 # define HvNAMELEN_get(H) strlen(HvNAME_get(H))
36 #endif
37
38 #ifndef SvREFCNT_inc_simple_NN
39 # define SvREFCNT_inc_simple_NN SvREFCNT_inc
40 #endif
41
42 #ifndef ENTER_with_name
43 # define ENTER_with_name(N) ENTER
44 #endif
45
46 #ifndef LEAVE_with_name
47 # define LEAVE_with_name(N) LEAVE
48 #endif
49
50 /* ... Thread safety and multiplicity ...................................... */
51
52 #ifndef LT_MULTIPLICITY
53 # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT)
54 #  define LT_MULTIPLICITY 1
55 # else
56 #  define LT_MULTIPLICITY 0
57 # endif
58 #endif
59 #if LT_MULTIPLICITY && !defined(tTHX)
60 # define tTHX PerlInterpreter*
61 #endif
62
63 #if LT_MULTIPLICITY && defined(USE_ITHREADS) && defined(dMY_CXT) && defined(MY_CXT) && defined(START_MY_CXT) && defined(MY_CXT_INIT) && (defined(MY_CXT_CLONE) || defined(dMY_CXT_SV))
64 # define LT_THREADSAFE 1
65 # ifndef MY_CXT_CLONE
66 #  define MY_CXT_CLONE \
67     dMY_CXT_SV;                                                      \
68     my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1)); \
69     Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t); \
70     sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
71 # endif
72 #else
73 # define LT_THREADSAFE 0
74 # undef  dMY_CXT
75 # define dMY_CXT      dNOOP
76 # undef  MY_CXT
77 # define MY_CXT       lt_globaldata
78 # undef  START_MY_CXT
79 # define START_MY_CXT STATIC my_cxt_t MY_CXT;
80 # undef  MY_CXT_INIT
81 # define MY_CXT_INIT  NOOP
82 # undef  MY_CXT_CLONE
83 # define MY_CXT_CLONE NOOP
84 # undef  pMY_CXT
85 # define pMY_CXT
86 # undef  pMY_CXT_
87 # define pMY_CXT_
88 # undef  aMY_CXT
89 # define aMY_CXT
90 # undef  aMY_CXT_
91 # define aMY_CXT_
92 #endif
93
94 /* --- Helpers ------------------------------------------------------------- */
95
96 /* ... Thread-safe hints ................................................... */
97
98 #if LT_WORKAROUND_REQUIRE_PROPAGATION
99
100 typedef struct {
101  SV *code;
102  IV  cxreq;
103 } lt_hint_t;
104
105 #define LT_HINT_STRUCT 1
106
107 #define LT_HINT_CODE(H) ((H)->code)
108
109 #define LT_HINT_FREE(H) { \
110  lt_hint_t *h = (H);      \
111  SvREFCNT_dec(h->code);   \
112  PerlMemShared_free(h);   \
113 }
114
115 #else  /*  LT_WORKAROUND_REQUIRE_PROPAGATION */
116
117 typedef SV lt_hint_t;
118
119 #define LT_HINT_STRUCT 0
120
121 #define LT_HINT_CODE(H) (H)
122
123 #define LT_HINT_FREE(H) SvREFCNT_dec(H);
124
125 #endif /* !LT_WORKAROUND_REQUIRE_PROPAGATION */
126
127 #if LT_THREADSAFE
128
129 #define PTABLE_NAME        ptable_hints
130 #define PTABLE_VAL_FREE(V) LT_HINT_FREE(V)
131
132 #define pPTBL  pTHX
133 #define pPTBL_ pTHX_
134 #define aPTBL  aTHX
135 #define aPTBL_ aTHX_
136
137 #include "ptable.h"
138
139 #define ptable_hints_store(T, K, V) ptable_hints_store(aTHX_ (T), (K), (V))
140 #define ptable_hints_free(T)        ptable_hints_free(aTHX_ (T))
141
142 #endif /* LT_THREADSAFE */
143
144 /* ... Global data ......................................................... */
145
146 #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
147
148 typedef struct {
149 #if LT_THREADSAFE
150  ptable *tbl; /* It really is a ptable_hints */
151  tTHX    owner;
152 #endif
153  SV     *default_meth;
154  OP *  (*pp_padsv_saved)(pTHX);
155 } my_cxt_t;
156
157 START_MY_CXT
158
159 /* ... Cloning global data ................................................. */
160
161 #if LT_THREADSAFE
162
163 STATIC SV *lt_clone(pTHX_ SV *sv, tTHX owner) {
164 #define lt_clone(S, O) lt_clone(aTHX_ (S), (O))
165  CLONE_PARAMS  param;
166  AV           *stashes = NULL;
167  SV           *dupsv;
168
169  if (SvTYPE(sv) == SVt_PVHV && HvNAME_get(sv))
170   stashes = newAV();
171
172  param.stashes    = stashes;
173  param.flags      = 0;
174  param.proto_perl = owner;
175
176  dupsv = sv_dup(sv, &param);
177
178  if (stashes) {
179   av_undef(stashes);
180   SvREFCNT_dec(stashes);
181  }
182
183  return SvREFCNT_inc(dupsv);
184 }
185
186 STATIC void lt_ptable_hints_clone(pTHX_ ptable_ent *ent, void *ud_) {
187  my_cxt_t  *ud  = ud_;
188  lt_hint_t *h1 = ent->val;
189  lt_hint_t *h2;
190
191  if (ud->owner == aTHX)
192   return;
193
194 #if LT_HINT_STRUCT
195
196  h2        = PerlMemShared_malloc(sizeof *h2);
197  h2->code  = lt_clone(h1->code, ud->owner);
198  SvREFCNT_inc(h2->code);
199 #if LT_WORKAROUND_REQUIRE_PROPAGATION
200  h2->cxreq = h1->cxreq;
201 #endif
202
203 #else /*   LT_HINT_STRUCT */
204
205  h2 = lt_clone(h1, ud->owner);
206  SvREFCNT_inc(h2);
207
208 #endif /* !LT_HINT_STRUCT */
209
210  ptable_hints_store(ud->tbl, ent->key, h2);
211 }
212
213 STATIC void lt_thread_cleanup(pTHX_ void *);
214
215 STATIC void lt_thread_cleanup(pTHX_ void *ud) {
216  int *level = ud;
217
218  if (*level) {
219   *level = 0;
220   LEAVE;
221   SAVEDESTRUCTOR_X(lt_thread_cleanup, level);
222   ENTER;
223  } else {
224   dMY_CXT;
225   PerlMemShared_free(level);
226   ptable_hints_free(MY_CXT.tbl);
227  }
228 }
229
230 #endif /* LT_THREADSAFE */
231
232 /* ... Hint tags ........................................................... */
233
234 #if LT_WORKAROUND_REQUIRE_PROPAGATION
235 STATIC IV lt_require_tag(pTHX) {
236 #define lt_require_tag() lt_require_tag(aTHX)
237  const PERL_SI *si;
238
239  for (si = PL_curstackinfo; si; si = si->si_prev) {
240   I32 cxix;
241
242   for (cxix = si->si_cxix; cxix >= 0; --cxix) {
243    const PERL_CONTEXT *cx = si->si_cxstack + cxix;
244
245    if (CxTYPE(cx) == CXt_EVAL && cx->blk_eval.old_op_type == OP_REQUIRE)
246     return PTR2IV(cx);
247   }
248  }
249
250  return PTR2IV(NULL);
251 }
252 #endif /* LT_WORKAROUND_REQUIRE_PROPAGATION */
253
254 STATIC SV *lt_tag(pTHX_ SV *value) {
255 #define lt_tag(V) lt_tag(aTHX_ (V))
256  lt_hint_t *h;
257  SV *code = NULL;
258  dMY_CXT;
259
260  if (SvROK(value)) {
261   value = SvRV(value);
262   if (SvTYPE(value) >= SVt_PVCV) {
263    code = value;
264    SvREFCNT_inc_simple_NN(code);
265   }
266  }
267
268 #if LT_HINT_STRUCT
269  h = PerlMemShared_malloc(sizeof *h);
270  h->code  = code;
271 # if LT_WORKAROUND_REQUIRE_PROPAGATION
272  h->cxreq = lt_require_tag();
273 # endif /* LT_WORKAROUND_REQUIRE_PROPAGATION */
274 #else  /*  LT_HINT_STRUCT */
275  h = code;
276 #endif /* !LT_HINT_STRUCT */
277
278 #if LT_THREADSAFE
279  /* We only need for the key to be an unique tag for looking up the value later.
280   * Allocated memory provides convenient unique identifiers, so that's why we
281   * use the hint as the key itself. */
282  ptable_hints_store(MY_CXT.tbl, h, h);
283 #endif /* LT_THREADSAFE */
284
285  return newSViv(PTR2IV(h));
286 }
287
288 STATIC SV *lt_detag(pTHX_ const SV *hint) {
289 #define lt_detag(H) lt_detag(aTHX_ (H))
290  lt_hint_t *h;
291  dMY_CXT;
292
293  if (!(hint && SvIOK(hint)))
294   return NULL;
295
296  h = INT2PTR(lt_hint_t *, SvIVX(hint));
297 #if LT_THREADSAFE
298  h = ptable_fetch(MY_CXT.tbl, h);
299 #endif /* LT_THREADSAFE */
300 #if LT_WORKAROUND_REQUIRE_PROPAGATION
301  if (lt_require_tag() != h->cxreq)
302   return NULL;
303 #endif /* LT_WORKAROUND_REQUIRE_PROPAGATION */
304
305  return LT_HINT_CODE(h);
306 }
307
308 STATIC U32 lt_hash = 0;
309
310 STATIC SV *lt_hint(pTHX) {
311 #define lt_hint() lt_hint(aTHX)
312  SV *hint;
313 #if LT_HAS_PERL(5, 9, 5)
314  hint = Perl_refcounted_he_fetch(aTHX_ PL_curcop->cop_hints_hash,
315                                        NULL,
316                                        __PACKAGE__, __PACKAGE_LEN__,
317                                        0,
318                                        lt_hash);
319 #else
320  SV **val = hv_fetch(GvHV(PL_hintgv), __PACKAGE__, __PACKAGE_LEN__, lt_hash);
321  if (!val)
322   return 0;
323  hint = *val;
324 #endif
325  return lt_detag(hint);
326 }
327
328 /* ... op => info map ...................................................... */
329
330 #define PTABLE_NAME        ptable_map
331 #define PTABLE_VAL_FREE(V) PerlMemShared_free(V)
332
333 #include "ptable.h"
334
335 /* PerlMemShared_free() needs the [ap]PTBLMS_? default values */
336 #define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V))
337
338 STATIC ptable *lt_op_map = NULL;
339
340 #ifdef USE_ITHREADS
341 STATIC perl_mutex lt_op_map_mutex;
342 #endif
343
344 typedef struct {
345 #ifdef MULTIPLICITY
346  STRLEN buf_size, orig_pkg_len, type_pkg_len, type_meth_len;
347  char *buf;
348 #else /* MULTIPLICITY */
349  SV *orig_pkg;
350  SV *type_pkg;
351  SV *type_meth;
352 #endif /* !MULTIPLICITY */
353  OP *(*old_pp_padsv)(pTHX);
354 } lt_op_info;
355
356 STATIC void lt_map_store(pTHX_ const OP *o, SV *orig_pkg, SV *type_pkg, SV *type_meth, OP *(*old_pp_padsv)(pTHX)) {
357 #define lt_map_store(O, OP, TP, TM, PP) lt_map_store(aTHX_ (O), (OP), (TP), (TM), (PP))
358  lt_op_info *oi;
359
360 #ifdef USE_ITHREADS
361  MUTEX_LOCK(&lt_op_map_mutex);
362 #endif
363
364  if (!(oi = ptable_fetch(lt_op_map, o))) {
365   oi = PerlMemShared_malloc(sizeof *oi);
366   ptable_map_store(lt_op_map, o, oi);
367 #ifdef MULTIPLICITY
368   oi->buf      = NULL;
369   oi->buf_size = 0;
370 #else /* MULTIPLICITY */
371  } else {
372   SvREFCNT_dec(oi->orig_pkg);
373   SvREFCNT_dec(oi->type_pkg);
374   SvREFCNT_dec(oi->type_meth);
375 #endif /* !MULTIPLICITY */
376  }
377
378 #ifdef MULTIPLICITY
379  {
380   STRLEN op_len       = SvCUR(orig_pkg);
381   STRLEN tp_len       = SvCUR(type_pkg);
382   STRLEN tm_len       = SvCUR(type_meth);
383   STRLEN new_buf_size = op_len + tp_len + tm_len;
384   char *buf;
385   if (new_buf_size > oi->buf_size) {
386    PerlMemShared_free(oi->buf);
387    oi->buf      = PerlMemShared_malloc(new_buf_size);
388    oi->buf_size = new_buf_size;
389   }
390   buf  = oi->buf;
391   Copy(SvPVX(orig_pkg),  buf, op_len, char);
392   buf += op_len;
393   Copy(SvPVX(type_pkg),  buf, tp_len, char);
394   buf += tp_len;
395   Copy(SvPVX(type_meth), buf, tm_len, char);
396   oi->orig_pkg_len  = op_len;
397   oi->type_pkg_len  = tp_len;
398   oi->type_meth_len = tm_len;
399   SvREFCNT_dec(orig_pkg);
400   SvREFCNT_dec(type_pkg);
401   SvREFCNT_dec(type_meth);
402  }
403 #else /* MULTIPLICITY */
404  oi->orig_pkg  = orig_pkg;
405  oi->type_pkg  = type_pkg;
406  oi->type_meth = type_meth;
407 #endif /* !MULTIPLICITY */
408
409  oi->old_pp_padsv = old_pp_padsv;
410
411 #ifdef USE_ITHREADS
412  MUTEX_UNLOCK(&lt_op_map_mutex);
413 #endif
414 }
415
416 STATIC const lt_op_info *lt_map_fetch(const OP *o, lt_op_info *oi) {
417  const lt_op_info *val;
418
419 #ifdef USE_ITHREADS
420  MUTEX_LOCK(&lt_op_map_mutex);
421 #endif
422
423  val = ptable_fetch(lt_op_map, o);
424  if (val) {
425   *oi = *val;
426   val = oi;
427  }
428
429 #ifdef USE_ITHREADS
430  MUTEX_UNLOCK(&lt_op_map_mutex);
431 #endif
432
433  return val;
434 }
435
436 STATIC void lt_map_delete(pTHX_ const OP *o) {
437 #define lt_map_delete(O) lt_map_delete(aTHX_ (O))
438 #ifdef USE_ITHREADS
439  MUTEX_LOCK(&lt_op_map_mutex);
440 #endif
441
442  ptable_map_store(lt_op_map, o, NULL);
443
444 #ifdef USE_ITHREADS
445  MUTEX_UNLOCK(&lt_op_map_mutex);
446 #endif
447 }
448
449 /* --- Hooks --------------------------------------------------------------- */
450
451 /* ... Our pp_padsv ........................................................ */
452
453 STATIC OP *lt_pp_padsv(pTHX) {
454  lt_op_info oi;
455
456  if ((PL_op->op_private & OPpLVAL_INTRO) && lt_map_fetch(PL_op, &oi)) {
457   PADOFFSET targ = PL_op->op_targ;
458   SV *sv         = PAD_SVl(targ);
459
460   if (sv) {
461    SV *orig_pkg, *type_pkg, *type_meth;
462    int items;
463    dSP;
464
465    ENTER;
466    SAVETMPS;
467
468 #ifdef MULTIPLICITY
469    {
470     STRLEN op_len = oi.orig_pkg_len, tp_len = oi.type_pkg_len;
471     char *buf = oi.buf;
472     orig_pkg  = sv_2mortal(newSVpvn(buf, op_len));
473     SvREADONLY_on(orig_pkg);
474     buf      += op_len;
475     type_pkg  = sv_2mortal(newSVpvn(buf, tp_len));
476     SvREADONLY_on(type_pkg);
477     buf      += tp_len;
478     type_meth = sv_2mortal(newSVpvn(buf, oi.type_meth_len));
479     SvREADONLY_on(type_meth);
480    }
481 #else /* MULTIPLICITY */
482    orig_pkg  = oi.orig_pkg;
483    type_pkg  = oi.type_pkg;
484    type_meth = oi.type_meth;
485 #endif /* !MULTIPLICITY */
486
487    PUSHMARK(SP);
488    EXTEND(SP, 3);
489    PUSHs(type_pkg);
490    PUSHs(sv);
491    PUSHs(orig_pkg);
492    PUTBACK;
493
494    items = call_sv(type_meth, G_ARRAY | G_METHOD);
495
496    SPAGAIN;
497    switch (items) {
498     case 0:
499      break;
500     case 1:
501      sv_setsv(sv, POPs);
502      break;
503     default:
504      croak("Typed scalar initializer method should return zero or one scalar, but got %d", items);
505    }
506    PUTBACK;
507
508    FREETMPS;
509    LEAVE;
510   }
511
512   return CALL_FPTR(oi.old_pp_padsv)(aTHX);
513  }
514
515  return CALL_FPTR(PL_ppaddr[OP_PADSV])(aTHX);
516 }
517
518 STATIC void lt_pp_padsv_save(pMY_CXT) {
519 #define lt_pp_padsv_save() lt_pp_padsv_save(aMY_CXT)
520  if (MY_CXT.pp_padsv_saved)
521   return;
522
523  MY_CXT.pp_padsv_saved = PL_ppaddr[OP_PADSV];
524  PL_ppaddr[OP_PADSV]   = lt_pp_padsv;
525 }
526
527 STATIC void lt_pp_padsv_restore(pMY_CXT_ OP *o) {
528 #define lt_pp_padsv_restore(O) lt_pp_padsv_restore(aMY_CXT_ (O))
529  OP *(*saved)(pTHX) = MY_CXT.pp_padsv_saved;
530
531  if (!saved)
532   return;
533
534  if (o->op_ppaddr == lt_pp_padsv)
535   o->op_ppaddr = saved;
536
537  PL_ppaddr[OP_PADSV]   = saved;
538  MY_CXT.pp_padsv_saved = 0;
539 }
540
541 /* ... Our ck_pad{any,sv} .................................................. */
542
543 /* Sadly, the PADSV OPs we are interested in don't trigger the padsv check
544  * function, but are instead manually mutated from a PADANY. This is why we set
545  * PL_ppaddr[OP_PADSV] in the padany check function so that PADSV OPs will have
546  * their pp_ppaddr set to our pp_padsv. PL_ppaddr[OP_PADSV] is then reset at the
547  * beginning of every ck_pad{any,sv}. Some unwanted OPs can still call our
548  * pp_padsv, but much less than if we would have set PL_ppaddr[OP_PADSV]
549  * globally. */
550
551 STATIC OP *(*lt_old_ck_padany)(pTHX_ OP *) = 0;
552
553 STATIC OP *lt_ck_padany(pTHX_ OP *o) {
554  HV *stash;
555  SV *code;
556  dMY_CXT;
557
558  lt_pp_padsv_restore(o);
559
560  o = CALL_FPTR(lt_old_ck_padany)(aTHX_ o);
561
562  stash = PL_in_my_stash;
563  if (stash && (code = lt_hint())) {
564   SV *orig_pkg  = newSVpvn(HvNAME_get(stash), HvNAMELEN_get(stash));
565   SV *orig_meth = MY_CXT.default_meth;
566   SV *type_pkg  = NULL;
567   SV *type_meth = NULL;
568   int items;
569
570   dSP;
571
572   SvREADONLY_on(orig_pkg);
573
574   ENTER;
575   SAVETMPS;
576
577   PUSHMARK(SP);
578   EXTEND(SP, 2);
579   PUSHs(orig_pkg);
580   PUSHs(orig_meth);
581   PUTBACK;
582
583   items = call_sv(code, G_ARRAY);
584
585   SPAGAIN;
586   if (items > 2)
587    croak(__PACKAGE__ " mangler should return zero, one or two scalars, but got %d", items);
588   if (items == 0) {
589    SvREFCNT_dec(orig_pkg);
590    FREETMPS;
591    LEAVE;
592    goto skip;
593   } else {
594    SV *rsv;
595    if (items > 1) {
596     rsv = POPs;
597     if (SvOK(rsv)) {
598      type_meth = newSVsv(rsv);
599      SvREADONLY_on(type_meth);
600     }
601    }
602    rsv = POPs;
603    if (SvOK(rsv)) {
604     type_pkg = newSVsv(rsv);
605     SvREADONLY_on(type_pkg);
606    }
607   }
608   PUTBACK;
609
610   FREETMPS;
611   LEAVE;
612
613   if (!type_pkg) {
614    type_pkg = orig_pkg;
615    SvREFCNT_inc(orig_pkg);
616   }
617
618   if (!type_meth) {
619    type_meth = orig_meth;
620    SvREFCNT_inc(orig_meth);
621   }
622
623   lt_pp_padsv_save();
624
625   lt_map_store(o, orig_pkg, type_pkg, type_meth, MY_CXT.pp_padsv_saved);
626  } else {
627 skip:
628   lt_map_delete(o);
629  }
630
631  return o;
632 }
633
634 STATIC OP *(*lt_old_ck_padsv)(pTHX_ OP *) = 0;
635
636 STATIC OP *lt_ck_padsv(pTHX_ OP *o) {
637  dMY_CXT;
638
639  lt_pp_padsv_restore(o);
640
641  lt_map_delete(o);
642
643  return CALL_FPTR(lt_old_ck_padsv)(aTHX_ o);
644 }
645
646 STATIC U32 lt_initialized = 0;
647
648 STATIC void lt_teardown(pTHX_ void *root) {
649  dMY_CXT;
650
651  if (!lt_initialized)
652   return;
653
654 #if LT_MULTIPLICITY
655  if (aTHX != root)
656   return;
657 #endif
658
659 #if LT_THREADSAFE
660  ptable_hints_free(MY_CXT.tbl);
661 #endif
662  SvREFCNT_dec(MY_CXT.default_meth);
663
664  PL_check[OP_PADANY] = MEMBER_TO_FPTR(lt_old_ck_padany);
665  lt_old_ck_padany    = 0;
666  PL_check[OP_PADSV]  = MEMBER_TO_FPTR(lt_old_ck_padsv);
667  lt_old_ck_padsv     = 0;
668
669  lt_initialized = 0;
670 }
671
672 STATIC void lt_setup(pTHX) {
673 #define lt_setup() lt_setup(aTHX)
674  if (lt_initialized)
675   return;
676
677  {
678   MY_CXT_INIT;
679 #if LT_THREADSAFE
680   MY_CXT.tbl            = ptable_new();
681   MY_CXT.owner          = aTHX;
682 #endif
683   MY_CXT.pp_padsv_saved = 0;
684   MY_CXT.default_meth   = newSVpvn("TYPEDSCALAR", 11);
685   SvREADONLY_on(MY_CXT.default_meth);
686  }
687
688  lt_old_ck_padany    = PL_check[OP_PADANY];
689  PL_check[OP_PADANY] = MEMBER_TO_FPTR(lt_ck_padany);
690  lt_old_ck_padsv     = PL_check[OP_PADSV];
691  PL_check[OP_PADSV]  = MEMBER_TO_FPTR(lt_ck_padsv);
692
693 #if LT_MULTIPLICITY
694  call_atexit(lt_teardown, aTHX);
695 #else
696  call_atexit(lt_teardown, NULL);
697 #endif
698
699  lt_initialized = 1;
700 }
701
702 STATIC U32 lt_booted = 0;
703
704 /* --- XS ------------------------------------------------------------------ */
705
706 MODULE = Lexical::Types      PACKAGE = Lexical::Types
707
708 PROTOTYPES: ENABLE
709
710 BOOT: 
711 {                                    
712  if (!lt_booted++) {
713   HV *stash;
714
715   lt_op_map = ptable_new();
716 #ifdef USE_ITHREADS
717   MUTEX_INIT(&lt_op_map_mutex);
718 #endif
719
720   PERL_HASH(lt_hash, __PACKAGE__, __PACKAGE_LEN__);
721
722   stash = gv_stashpvn(__PACKAGE__, __PACKAGE_LEN__, 1);
723   newCONSTSUB(stash, "LT_THREADSAFE", newSVuv(LT_THREADSAFE));
724  }
725
726  lt_setup();
727 }
728
729 #if LT_THREADSAFE
730
731 void
732 CLONE(...)
733 PROTOTYPE: DISABLE
734 PREINIT:
735  ptable *t;
736  int    *level;
737  SV     *cloned_default_meth;
738 PPCODE:
739  {
740   my_cxt_t ud;
741   dMY_CXT;
742   ud.tbl   = t = ptable_new();
743   ud.owner = MY_CXT.owner;
744   ptable_walk(MY_CXT.tbl, lt_ptable_hints_clone, &ud);
745   cloned_default_meth = lt_clone(MY_CXT.default_meth, MY_CXT.owner);
746  }
747  {
748   MY_CXT_CLONE;
749   MY_CXT.tbl            = t;
750   MY_CXT.owner          = aTHX;
751   MY_CXT.pp_padsv_saved = 0;
752   MY_CXT.default_meth   = cloned_default_meth;
753  }
754  {
755   level = PerlMemShared_malloc(sizeof *level);
756   *level = 1;
757   LEAVE_with_name("sub");
758   SAVEDESTRUCTOR_X(lt_thread_cleanup, level);
759   ENTER_with_name("sub");
760  }
761  XSRETURN(0);
762
763 #endif
764
765 SV *
766 _tag(SV *value)
767 PROTOTYPE: $
768 CODE:
769  RETVAL = lt_tag(value);
770 OUTPUT:
771  RETVAL