4 #include "caps.h" /* XSH_HAS_PERL(), XSH_THREADSAFE, tTHX */
7 # error threads.h must be loaded at the very end
10 #define XSH_HINTS_KEY XSH_PACKAGE
11 #define XSH_HINTS_KEY_LEN (sizeof(XSH_HINTS_KEY)-1)
13 #ifndef XSH_WORKAROUND_REQUIRE_PROPAGATION
14 # define XSH_WORKAROUND_REQUIRE_PROPAGATION !XSH_HAS_PERL(5, 10, 1)
17 #ifndef XSH_HINTS_ONLY_COMPILE_TIME
18 # define XSH_HINTS_ONLY_COMPILE_TIME 1
21 #ifdef XSH_HINTS_TYPE_UV
22 # ifdef XSH_HINTS_TYPE_VAL
23 # error hint type can only be set once
25 # undef XSH_HINTS_TYPE_UV
26 # define XSH_HINTS_TYPE_UV 1
27 # define XSH_HINTS_TYPE_STRUCT UV
28 # define XSH_HINTS_TYPE_COMPACT UV
29 # define XSH_HINTS_NEED_STRUCT 0
30 # define XSH_HINTS_VAL_STRUCT_REF 0
31 # define XSH_HINTS_VAL_NONE 0
32 # define XSH_HINTS_VAL_PACK(T, V) INT2PTR(T, (V))
33 # define XSH_HINTS_VAL_UNPACK(V) ((XSH_HINTS_TYPE_VAL) PTR2UV(V))
34 # define XSH_HINTS_VAL_INIT(HV, V) ((HV) = (V))
35 # undef XSH_HINTS_VAL_CLONE
36 # undef XSH_HINTS_VAL_DEINIT
39 #ifdef XSH_HINTS_TYPE_SV
40 # ifdef XSH_HINTS_TYPE_VAL
41 # error hint type can only be set once
43 # undef XSH_HINTS_TYPE_SV
44 # define XSH_HINTS_TYPE_SV 1
45 # define XSH_HINTS_TYPE_STRUCT SV *
46 # define XSH_HINTS_TYPE_COMPACT SV
47 # define XSH_HINTS_NEED_STRUCT 0
48 # define XSH_HINTS_VAL_STRUCT_REF 0
49 # define XSH_HINTS_VAL_NONE NULL
50 # define XSH_HINTS_VAL_PACK(T, V) (V)
51 # define XSH_HINTS_VAL_UNPACK(V) (V)
52 # define XSH_HINTS_VAL_INIT(HV, V) ((HV) = (((V) != XSH_HINTS_VAL_NONE) ? SvREFCNT_inc(V) : XSH_HINTS_VAL_NONE))
53 # define XSH_HINTS_VAL_CLONE(N, O) ((N) = xsh_dup_inc((O), ud->params))
54 # define XSH_HINTS_VAL_DEINIT(V) SvREFCNT_dec(V)
57 #ifdef XSH_HINTS_TYPE_USER
58 # ifdef XSH_HINTS_TYPE_VAL
59 # error hint type can only be set once
61 # undef XSH_HINTS_TYPE_USER
62 # define XSH_HINTS_TYPE_USER 1
63 # define XSH_HINTS_TYPE_STRUCT xsh_hints_user_t
64 # undef XSH_HINTS_TYPE_COMPACT /* not used */
65 # define XSH_HINTS_NEED_STRUCT 1
66 # define XSH_HINTS_VAL_STRUCT_REF 1
67 # define XSH_HINTS_VAL_NONE NULL
68 # define XSH_HINTS_VAL_PACK(T, V) (V)
69 # define XSH_HINTS_VAL_UNPACK(V) (V)
70 # define XSH_HINTS_VAL_INIT(HV, V) xsh_hints_user_init(aTHX_ (HV), (V))
71 # define XSH_HINTS_VAL_CLONE(NV, OV) xsh_hints_user_clone(aTHX_ (NV), (OV), ud->params)
72 # define XSH_HINTS_VAL_DEINIT(V) xsh_hints_user_deinit(aTHX_ (V))
75 #ifndef XSH_HINTS_TYPE_STRUCT
76 # error hint type was not set
79 #if XSH_HINTS_VAL_STRUCT_REF
80 # define XSH_HINTS_TYPE_VAL XSH_HINTS_TYPE_STRUCT *
82 # define XSH_HINTS_TYPE_VAL XSH_HINTS_TYPE_STRUCT
85 #if XSH_WORKAROUND_REQUIRE_PROPAGATION
86 # undef XSH_HINTS_NEED_STRUCT
87 # define XSH_HINTS_NEED_STRUCT 1
90 #if XSH_THREADSAFE && (defined(XSH_HINTS_VAL_CLONE) || XSH_WORKAROUND_REQUIRE_PROPAGATION)
91 # define XSH_HINTS_NEED_CLONE 1
93 # define XSH_HINTS_NEED_CLONE 0
96 #if XSH_WORKAROUND_REQUIRE_PROPAGATION
98 static UV xsh_require_tag(pTHX) {
99 #define xsh_require_tag() xsh_require_tag(aTHX)
100 const CV *cv, *outside;
105 /* If for some reason the pragma is operational at run-time, try to discover
106 * the current cv in use. */
109 for (si = PL_curstackinfo; si; si = si->si_prev) {
112 for (cxix = si->si_cxix; cxix >= 0; --cxix) {
113 const PERL_CONTEXT *cx = si->si_cxstack + cxix;
115 switch (CxTYPE(cx)) {
118 /* The propagation workaround is only needed up to 5.10.0 and at that
119 * time format and sub contexts were still identical. And even later the
120 * cv members offsets should have been kept the same. */
122 goto get_enclosing_cv;
124 cv = cx->blk_eval.cv;
125 goto get_enclosing_cv;
136 for (outside = CvOUTSIDE(cv); outside; outside = CvOUTSIDE(cv))
142 #endif /* XSH_WORKAROUND_REQUIRE_PROPAGATION */
144 #if XSH_HINTS_NEED_STRUCT
147 XSH_HINTS_TYPE_STRUCT val;
148 #if XSH_WORKAROUND_REQUIRE_PROPAGATION
153 #if XSH_HINTS_VAL_STRUCT_REF
154 # define XSH_HINTS_VAL_GET(H) (&(H)->val)
156 # define XSH_HINTS_VAL_GET(H) ((H)->val)
159 #define XSH_HINTS_VAL_SET(H, V) XSH_HINTS_VAL_INIT(XSH_HINTS_VAL_GET(H), (V))
161 #ifdef XSH_HINTS_VAL_DEINIT
162 # define XSH_HINTS_FREE(H) \
163 if (H) XSH_HINTS_VAL_DEINIT(XSH_HINTS_VAL_GET(H)); \
164 PerlMemShared_free(H)
166 # define XSH_HINTS_FREE(H) PerlMemShared_free(H)
169 #else /* XSH_HINTS_NEED_STRUCT */
171 typedef XSH_HINTS_TYPE_COMPACT xsh_hints_t;
173 #define XSH_HINTS_VAL_GET(H) XSH_HINTS_VAL_UNPACK(H)
174 #define XSH_HINTS_VAL_SET(H, V) STMT_START { XSH_HINTS_TYPE_VAL tmp; XSH_HINTS_VAL_INIT(tmp, (V)); (H) = XSH_HINTS_VAL_PACK(xsh_hints_t *, tmp); } STMT_END
176 #undef XSH_HINTS_FREE
178 #endif /* !XSH_HINTS_NEED_STRUCT */
180 /* ... Thread safety ....................................................... */
182 #if XSH_HINTS_NEED_CLONE
184 #ifdef XSH_HINTS_FREE
185 # define PTABLE_NAME ptable_hints
186 # define PTABLE_VAL_FREE(V) XSH_HINTS_FREE((xsh_hints_t *) (V))
188 # define PTABLE_USE_DEFAULT 1
191 #define PTABLE_NEED_WALK 1
192 #define PTABLE_NEED_DELETE 0
196 #if PTABLE_WAS_DEFAULT
197 # define ptable_hints_store(T, K, V) ptable_default_store(aPTBL_ (T), (K), (V))
198 # define ptable_hints_free(T) ptable_default_free(aPTBL_ (T))
200 # define ptable_hints_store(T, K, V) ptable_hints_store(aPTBL_ (T), (K), (V))
201 # define ptable_hints_free(T) ptable_hints_free(aPTBL_ (T))
204 #define XSH_THREADS_HINTS_CONTEXT 1
207 ptable *tbl; /* It really is a ptable_hints */
211 static xsh_hints_cxt_t *xsh_hints_get_cxt(pTHX);
213 static void xsh_hints_local_setup(pTHX_ xsh_hints_cxt_t *cxt) {
214 cxt->tbl = ptable_new(4);
218 static void xsh_hints_local_teardown(pTHX_ xsh_hints_cxt_t *cxt) {
219 ptable_hints_free(cxt->tbl);
224 ptable *tbl; /* It really is a ptable_hints */
225 CLONE_PARAMS *params;
226 } xsh_ptable_clone_ud;
228 static void xsh_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
229 xsh_ptable_clone_ud *ud = ud_;
230 xsh_hints_t *h1 = ent->val;
233 #if XSH_HINTS_NEED_STRUCT
234 h2 = PerlMemShared_malloc(sizeof *h2);
235 # if XSH_WORKAROUND_REQUIRE_PROPAGATION
236 h2->require_tag = PTR2UV(xsh_dup_inc(INT2PTR(SV *, h1->require_tag), ud->params));
238 #endif /* XSH_HINTS_NEED_STRUCT */
240 #ifdef XSH_HINTS_VAL_CLONE
241 XSH_HINTS_VAL_CLONE(XSH_HINTS_VAL_GET(h2), XSH_HINTS_VAL_GET(h1));
242 #endif /* defined(XSH_HINTS_VAL_CLONE) */
244 ptable_hints_store(ud->tbl, ent->key, h2);
247 static void xsh_hints_clone(pTHX_ const xsh_hints_cxt_t *old_cxt, xsh_hints_cxt_t *new_cxt, CLONE_PARAMS *params) {
248 xsh_ptable_clone_ud ud;
250 new_cxt->tbl = ptable_new(4);
251 new_cxt->owner = aTHX;
253 ud.tbl = new_cxt->tbl;
256 ptable_walk(old_cxt->tbl, xsh_ptable_clone, &ud);
259 #endif /* XSH_HINTS_NEED_CLONE */
261 /* ... tag hints ........................................................... */
263 static SV *xsh_hints_tag(pTHX_ XSH_HINTS_TYPE_VAL val) {
264 #define xsh_hints_tag(V) xsh_hints_tag(aTHX_ (V))
267 if (val == XSH_HINTS_VAL_NONE)
270 #if XSH_HINTS_NEED_STRUCT
271 h = PerlMemShared_malloc(sizeof *h);
272 # if XSH_WORKAROUND_REQUIRE_PROPAGATION
273 h->require_tag = xsh_require_tag();
275 #endif /* XSH_HINTS_NEED_STRUCT */
277 XSH_HINTS_VAL_SET(h, val);
279 #if XSH_HINTS_NEED_CLONE
280 /* We only need for the key to be an unique tag for looking up the value later
281 * Allocated memory provides convenient unique identifiers, so that's why we
282 * use the hint as the key itself. */
284 xsh_hints_cxt_t *cxt = xsh_hints_get_cxt(aTHX);
285 XSH_ASSERT(cxt->tbl);
286 ptable_hints_store(cxt->tbl, h, h);
288 #endif /* !XSH_HINTS_NEED_CLONE */
290 return newSVuv(PTR2UV(h));
293 /* ... detag hints ......................................................... */
295 #define xsh_hints_2uv(H) \
300 ? sv_2uv(SvLEN(H) ? (H) : sv_mortalcopy(H)) \
306 static XSH_HINTS_TYPE_VAL xsh_hints_detag(pTHX_ SV *hint) {
307 #define xsh_hints_detag(H) xsh_hints_detag(aTHX_ (H))
311 hint_uv = xsh_hints_2uv(hint);
312 h = INT2PTR(xsh_hints_t *, hint_uv);
314 return XSH_HINTS_VAL_NONE;
316 #if XSH_HINTS_NEED_CLONE
318 xsh_hints_cxt_t *cxt = xsh_hints_get_cxt(aTHX);
319 XSH_ASSERT(cxt->tbl);
320 h = ptable_fetch(cxt->tbl, h);
322 #endif /* XSH_HINTS_NEED_CLONE */
324 #if XSH_WORKAROUND_REQUIRE_PROPAGATION
325 if (xsh_require_tag() != h->require_tag)
326 return XSH_HINTS_VAL_NONE;
329 return XSH_HINTS_VAL_GET(h);
332 /* ... fetch hints ......................................................... */
334 #if !defined(cop_hints_fetch_pvn) && XSH_HAS_PERL(5, 9, 5)
335 # define cop_hints_fetch_pvn(COP, PKG, PKGLEN, PKGHASH, FLAGS) \
336 Perl_refcounted_he_fetch(aTHX_ (COP)->cop_hints_hash, NULL, \
337 (PKG), (PKGLEN), (FLAGS), (PKGHASH))
340 #ifdef cop_hints_fetch_pvn
342 static U32 xsh_hints_key_hash = 0;
343 # define xsh_hints_global_setup(my_perl) \
344 PERL_HASH(xsh_hints_key_hash, XSH_HINTS_KEY, XSH_HINTS_KEY_LEN)
346 #else /* defined(cop_hints_fetch_pvn) */
348 # define xsh_hints_global_setup(my_perl)
350 #endif /* !defined(cop_hints_fetch_pvn) */
352 #define xsh_hints_global_teardown(my_perl)
354 static SV *xsh_hints_fetch(pTHX) {
355 #define xsh_hints_fetch() xsh_hints_fetch(aTHX)
356 #if XSH_HINTS_ONLY_COMPILE_TIME
361 #ifdef cop_hints_fetch_pvn
362 return cop_hints_fetch_pvn(PL_curcop, XSH_HINTS_KEY, XSH_HINTS_KEY_LEN,
363 xsh_hints_key_hash, 0);
366 SV **val = hv_fetch(GvHV(PL_hintgv), XSH_HINTS_KEY, XSH_HINTS_KEY_LEN, 0);
367 return val ? *val : NULL;
372 #endif /* XSH_HINTS_H */