1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
|
#ifndef XSH_HINTS_H
#define XSH_HINTS_H 1
#include "caps.h" /* XSH_HAS_PERL(), XSH_THREADSAFE, tTHX */
#include "mem.h" /* XSH_SHARED_*() */
#ifdef XSH_THREADS_H
# error threads.h must be loaded at the very end
#endif
#define XSH_HINTS_KEY XSH_PACKAGE
#define XSH_HINTS_KEY_LEN (sizeof(XSH_HINTS_KEY)-1)
#ifndef XSH_WORKAROUND_REQUIRE_PROPAGATION
# define XSH_WORKAROUND_REQUIRE_PROPAGATION !XSH_HAS_PERL(5, 10, 1)
#endif
#ifndef XSH_HINTS_ONLY_COMPILE_TIME
# define XSH_HINTS_ONLY_COMPILE_TIME 1
#endif
#ifdef XSH_HINTS_TYPE_UV
# ifdef XSH_HINTS_TYPE_VAL
# error hint type can only be set once
# endif
# undef XSH_HINTS_TYPE_UV
# define XSH_HINTS_TYPE_UV 1
# define XSH_HINTS_TYPE_STRUCT UV
# define XSH_HINTS_TYPE_COMPACT UV
# define XSH_HINTS_NEED_STRUCT 0
# define XSH_HINTS_VAL_STRUCT_REF 0
# define XSH_HINTS_VAL_NONE 0
# define XSH_HINTS_VAL_PACK(T, V) INT2PTR(T, (V))
# define XSH_HINTS_VAL_UNPACK(V) ((XSH_HINTS_TYPE_VAL) PTR2UV(V))
# define XSH_HINTS_VAL_INIT(HV, V) ((HV) = (V))
# undef XSH_HINTS_VAL_CLONE
# undef XSH_HINTS_VAL_DEINIT
#endif
#ifdef XSH_HINTS_TYPE_SV
# ifdef XSH_HINTS_TYPE_VAL
# error hint type can only be set once
# endif
# undef XSH_HINTS_TYPE_SV
# define XSH_HINTS_TYPE_SV 1
# define XSH_HINTS_TYPE_STRUCT SV *
# define XSH_HINTS_TYPE_COMPACT SV
# define XSH_HINTS_NEED_STRUCT 0
# define XSH_HINTS_VAL_STRUCT_REF 0
# define XSH_HINTS_VAL_NONE NULL
# define XSH_HINTS_VAL_PACK(T, V) (V)
# define XSH_HINTS_VAL_UNPACK(V) (V)
# define XSH_HINTS_VAL_INIT(HV, V) ((HV) = (((V) != XSH_HINTS_VAL_NONE) ? SvREFCNT_inc(V) : XSH_HINTS_VAL_NONE))
# define XSH_HINTS_VAL_CLONE(N, O) ((N) = xsh_dup_inc((O), ud->params))
# define XSH_HINTS_VAL_DEINIT(V) SvREFCNT_dec(V)
#endif
#ifdef XSH_HINTS_TYPE_USER
# ifdef XSH_HINTS_TYPE_VAL
# error hint type can only be set once
# endif
# undef XSH_HINTS_TYPE_USER
# define XSH_HINTS_TYPE_USER 1
# define XSH_HINTS_TYPE_STRUCT xsh_hints_user_t
# undef XSH_HINTS_TYPE_COMPACT /* not used */
# define XSH_HINTS_NEED_STRUCT 1
# define XSH_HINTS_VAL_STRUCT_REF 1
# define XSH_HINTS_VAL_NONE NULL
# define XSH_HINTS_VAL_PACK(T, V) (V)
# define XSH_HINTS_VAL_UNPACK(V) (V)
# define XSH_HINTS_VAL_INIT(HV, V) xsh_hints_user_init(aTHX_ (HV), (V))
# define XSH_HINTS_VAL_CLONE(NV, OV) xsh_hints_user_clone(aTHX_ (NV), (OV), ud->params)
# define XSH_HINTS_VAL_DEINIT(V) xsh_hints_user_deinit(aTHX_ (V))
#endif
#ifndef XSH_HINTS_TYPE_STRUCT
# error hint type was not set
#endif
#if XSH_HINTS_VAL_STRUCT_REF
# define XSH_HINTS_TYPE_VAL XSH_HINTS_TYPE_STRUCT *
#else
# define XSH_HINTS_TYPE_VAL XSH_HINTS_TYPE_STRUCT
#endif
#if XSH_WORKAROUND_REQUIRE_PROPAGATION
# undef XSH_HINTS_NEED_STRUCT
# define XSH_HINTS_NEED_STRUCT 1
#endif
#if XSH_THREADSAFE && (defined(XSH_HINTS_VAL_CLONE) || XSH_WORKAROUND_REQUIRE_PROPAGATION)
# define XSH_HINTS_NEED_CLONE 1
#else
# define XSH_HINTS_NEED_CLONE 0
#endif
#if XSH_WORKAROUND_REQUIRE_PROPAGATION
static UV xsh_require_tag(pTHX) {
#define xsh_require_tag() xsh_require_tag(aTHX)
const CV *cv, *outside;
cv = PL_compcv;
if (!cv) {
/* If for some reason the pragma is operational at run-time, try to discover
* the current cv in use. */
const PERL_SI *si;
for (si = PL_curstackinfo; si; si = si->si_prev) {
I32 cxix;
for (cxix = si->si_cxix; cxix >= 0; --cxix) {
const PERL_CONTEXT *cx = si->si_cxstack + cxix;
switch (CxTYPE(cx)) {
case CXt_SUB:
case CXt_FORMAT:
/* The propagation workaround is only needed up to 5.10.0 and at that
* time format and sub contexts were still identical. And even later the
* cv members offsets should have been kept the same. */
cv = cx->blk_sub.cv;
goto get_enclosing_cv;
case CXt_EVAL:
cv = cx->blk_eval.cv;
goto get_enclosing_cv;
default:
break;
}
}
}
cv = PL_main_cv;
}
get_enclosing_cv:
for (outside = CvOUTSIDE(cv); outside; outside = CvOUTSIDE(cv))
cv = outside;
return PTR2UV(cv);
}
#endif /* XSH_WORKAROUND_REQUIRE_PROPAGATION */
#if XSH_HINTS_NEED_STRUCT
typedef struct {
XSH_HINTS_TYPE_STRUCT val;
#if XSH_WORKAROUND_REQUIRE_PROPAGATION
UV require_tag;
#endif
} xsh_hints_t;
#if XSH_HINTS_VAL_STRUCT_REF
# define XSH_HINTS_VAL_GET(H) (&(H)->val)
#else
# define XSH_HINTS_VAL_GET(H) ((H)->val)
#endif
#define XSH_HINTS_VAL_SET(H, V) XSH_HINTS_VAL_INIT(XSH_HINTS_VAL_GET(H), (V))
#ifdef XSH_HINTS_VAL_DEINIT
# define XSH_HINTS_FREE(H) \
if (H) XSH_HINTS_VAL_DEINIT(XSH_HINTS_VAL_GET(((xsh_hints_t *) (H)))); \
XSH_SHARED_FREE((H), 1, xsh_hints_t)
#else
# define XSH_HINTS_FREE(H) XSH_SHARED_FREE((H), 1, xsh_hints_t)
#endif
#else /* XSH_HINTS_NEED_STRUCT */
typedef XSH_HINTS_TYPE_COMPACT xsh_hints_t;
#define XSH_HINTS_VAL_GET(H) XSH_HINTS_VAL_UNPACK(H)
#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
#undef XSH_HINTS_FREE
#endif /* !XSH_HINTS_NEED_STRUCT */
/* ... Thread safety ....................................................... */
#if XSH_HINTS_NEED_CLONE
#ifdef XSH_HINTS_FREE
# define PTABLE_NAME ptable_hints
# define PTABLE_VAL_FREE(V) XSH_HINTS_FREE(V)
#else
# define PTABLE_USE_DEFAULT 1
#endif
#define PTABLE_NEED_WALK 1
#define PTABLE_NEED_DELETE 0
#include "ptable.h"
#if PTABLE_WAS_DEFAULT
# define ptable_hints_store(T, K, V) ptable_default_store(aPTBL_ (T), (K), (V))
# define ptable_hints_free(T) ptable_default_free(aPTBL_ (T))
#else
# define ptable_hints_store(T, K, V) ptable_hints_store(aPTBL_ (T), (K), (V))
# define ptable_hints_free(T) ptable_hints_free(aPTBL_ (T))
#endif
#define XSH_THREADS_HINTS_CONTEXT 1
typedef struct {
ptable *tbl; /* It really is a ptable_hints */
tTHX owner;
} xsh_hints_cxt_t;
static xsh_hints_cxt_t *xsh_hints_get_cxt(pTHX);
static void xsh_hints_local_setup(pTHX_ xsh_hints_cxt_t *cxt) {
cxt->tbl = ptable_new(4);
cxt->owner = aTHX;
}
static void xsh_hints_local_teardown(pTHX_ xsh_hints_cxt_t *cxt) {
ptable_hints_free(cxt->tbl);
cxt->owner = NULL;
}
typedef struct {
ptable *tbl; /* It really is a ptable_hints */
CLONE_PARAMS *params;
} xsh_ptable_clone_ud;
static void xsh_ptable_clone(pTHX_ ptable_ent *ent, void *ud_) {
xsh_ptable_clone_ud *ud = ud_;
xsh_hints_t *h1 = ent->val;
xsh_hints_t *h2;
#if XSH_HINTS_NEED_STRUCT
XSH_SHARED_ALLOC(h2, 1, xsh_hints_t);
# if XSH_WORKAROUND_REQUIRE_PROPAGATION
h2->require_tag = PTR2UV(xsh_dup_inc(INT2PTR(SV *, h1->require_tag), ud->params));
# endif
#endif /* XSH_HINTS_NEED_STRUCT */
#ifdef XSH_HINTS_VAL_CLONE
XSH_HINTS_VAL_CLONE(XSH_HINTS_VAL_GET(h2), XSH_HINTS_VAL_GET(h1));
#endif /* defined(XSH_HINTS_VAL_CLONE) */
ptable_hints_store(ud->tbl, ent->key, h2);
}
static void xsh_hints_clone(pTHX_ const xsh_hints_cxt_t *old_cxt, xsh_hints_cxt_t *new_cxt, CLONE_PARAMS *params) {
xsh_ptable_clone_ud ud;
new_cxt->tbl = ptable_new(4);
new_cxt->owner = aTHX;
ud.tbl = new_cxt->tbl;
ud.params = params;
ptable_walk(old_cxt->tbl, xsh_ptable_clone, &ud);
}
#endif /* XSH_HINTS_NEED_CLONE */
/* ... tag hints ........................................................... */
static SV *xsh_hints_tag(pTHX_ XSH_HINTS_TYPE_VAL val) {
#define xsh_hints_tag(V) xsh_hints_tag(aTHX_ (V))
xsh_hints_t *h;
if (val == XSH_HINTS_VAL_NONE)
return newSVuv(0);
#if XSH_HINTS_NEED_STRUCT
XSH_SHARED_ALLOC(h, 1, xsh_hints_t);
# if XSH_WORKAROUND_REQUIRE_PROPAGATION
h->require_tag = xsh_require_tag();
# endif
#endif /* XSH_HINTS_NEED_STRUCT */
XSH_HINTS_VAL_SET(h, val);
#if XSH_HINTS_NEED_CLONE
/* We only need for the key to be an unique tag for looking up the value later
* Allocated memory provides convenient unique identifiers, so that's why we
* use the hint as the key itself. */
{
xsh_hints_cxt_t *cxt = xsh_hints_get_cxt(aTHX);
XSH_ASSERT(cxt->tbl);
ptable_hints_store(cxt->tbl, h, h);
}
#endif /* !XSH_HINTS_NEED_CLONE */
return newSVuv(PTR2UV(h));
}
/* ... detag hints ......................................................... */
#define xsh_hints_2uv(H) \
((H) \
? (SvIOK(H) \
? SvUVX(H) \
: (SvPOK(H) \
? sv_2uv(SvLEN(H) ? (H) : sv_mortalcopy(H)) \
: 0 \
) \
) \
: 0)
static XSH_HINTS_TYPE_VAL xsh_hints_detag(pTHX_ SV *hint) {
#define xsh_hints_detag(H) xsh_hints_detag(aTHX_ (H))
xsh_hints_t *h;
UV hint_uv;
hint_uv = xsh_hints_2uv(hint);
h = INT2PTR(xsh_hints_t *, hint_uv);
if (!h)
return XSH_HINTS_VAL_NONE;
#if XSH_HINTS_NEED_CLONE
{
xsh_hints_cxt_t *cxt = xsh_hints_get_cxt(aTHX);
XSH_ASSERT(cxt->tbl);
h = ptable_fetch(cxt->tbl, h);
}
#endif /* XSH_HINTS_NEED_CLONE */
#if XSH_WORKAROUND_REQUIRE_PROPAGATION
if (xsh_require_tag() != h->require_tag)
return XSH_HINTS_VAL_NONE;
#endif
return XSH_HINTS_VAL_GET(h);
}
/* ... fetch hints ......................................................... */
#if !defined(cop_hints_fetch_pvn) && XSH_HAS_PERL(5, 9, 5)
# define cop_hints_fetch_pvn(COP, PKG, PKGLEN, PKGHASH, FLAGS) \
Perl_refcounted_he_fetch(aTHX_ (COP)->cop_hints_hash, NULL, \
(PKG), (PKGLEN), (FLAGS), (PKGHASH))
#endif
#ifdef cop_hints_fetch_pvn
static U32 xsh_hints_key_hash = 0;
# define xsh_hints_global_setup(my_perl) \
PERL_HASH(xsh_hints_key_hash, XSH_HINTS_KEY, XSH_HINTS_KEY_LEN)
#else /* defined(cop_hints_fetch_pvn) */
# define xsh_hints_global_setup(my_perl)
#endif /* !defined(cop_hints_fetch_pvn) */
#define xsh_hints_global_teardown(my_perl)
static SV *xsh_hints_fetch(pTHX) {
#define xsh_hints_fetch() xsh_hints_fetch(aTHX)
#if XSH_HINTS_ONLY_COMPILE_TIME
if (IN_PERL_RUNTIME)
return NULL;
#endif
#ifdef cop_hints_fetch_pvn
return cop_hints_fetch_pvn(PL_curcop, XSH_HINTS_KEY, XSH_HINTS_KEY_LEN,
xsh_hints_key_hash, 0);
#else
{
SV **val = hv_fetch(GvHV(PL_hintgv), XSH_HINTS_KEY, XSH_HINTS_KEY_LEN, 0);
return val ? *val : NULL;
}
#endif
}
#endif /* XSH_HINTS_H */
|