line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#include "util.h" |
2
|
|
|
|
|
|
|
#include |
3
|
|
|
|
|
|
|
#include |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
using namespace panda; |
6
|
|
|
|
|
|
|
using namespace panda::log; |
7
|
|
|
|
|
|
|
using panda::log::Level; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
namespace xs { namespace xlog { |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
#define OP_NA (OP_max + 1) |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
using backend_t = std::add_pointer::type; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
using Args = std::vector; |
16
|
|
|
|
|
|
|
using Optimizer = std::function; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
static Sv::payload_marker_t module_cache_marker; |
19
|
|
|
|
|
|
|
|
20
|
97
|
|
|
|
|
|
bool has_module (SV* ref) { |
21
|
97
|
100
|
|
|
|
|
if (SvOBJECT(ref)) { |
22
|
92
|
|
|
|
|
|
auto stash = SvSTASH(ref); |
23
|
92
|
50
|
|
|
|
|
return string_view(HvNAME(stash), HvNAMELEN(stash)) == "XLog::Module"; |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
24
|
|
|
|
|
|
|
} |
25
|
97
|
|
|
|
|
|
return false; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
201
|
|
|
|
|
|
Module* get_module_by_namespace (Stash stash) { |
29
|
201
|
|
|
|
|
|
auto module = (Module*)stash.payload(&module_cache_marker).ptr; // try to get module from cache |
30
|
201
|
100
|
|
|
|
|
if (module) return module; |
31
|
|
|
|
|
|
|
|
32
|
216
|
|
|
|
|
|
Object module_obj; |
33
|
15
|
|
|
|
|
|
auto name = stash.name(); |
34
|
|
|
|
|
|
|
|
35
|
17
|
|
|
|
|
|
while (1) { |
36
|
39
|
50
|
|
|
|
|
auto pkg = Stash(name); |
37
|
32
|
50
|
|
|
|
|
if (pkg) { |
38
|
64
|
50
|
|
|
|
|
auto val = pkg.fetch("xlog_module").scalar(); |
|
|
50
|
|
|
|
|
|
39
|
32
|
100
|
|
|
|
|
if (val && val.is_object_ref()) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
40
|
39
|
50
|
|
|
|
|
Object o = val; |
|
|
100
|
|
|
|
|
|
41
|
7
|
50
|
|
|
|
|
if (o.stash().name() == "XLog::Module") { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
42
|
6
|
50
|
|
|
|
|
module = xs::in(o); |
43
|
6
|
50
|
|
|
|
|
module_obj = o; |
44
|
7
|
100
|
|
|
|
|
break; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
} |
48
|
26
|
100
|
|
|
|
|
if (!name.length()) break; // stop after main:: |
49
|
17
|
50
|
|
|
|
|
auto pos = name.rfind("::"); |
50
|
17
|
100
|
|
|
|
|
if (pos == string_view::npos) { // look in main:: |
51
|
10
|
|
|
|
|
|
name = ""; |
52
|
10
|
|
|
|
|
|
continue; |
53
|
|
|
|
|
|
|
} |
54
|
32
|
50
|
|
|
|
|
name = name.substr(0, pos); |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
25
|
100
|
|
|
|
|
if (!module) module = &::panda_log_module; |
58
|
15
|
50
|
|
|
|
|
stash.payload_attach((void*)module, module_obj, &module_cache_marker); |
59
|
|
|
|
|
|
|
|
60
|
15
|
|
|
|
|
|
return module; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
201
|
|
|
|
|
|
Module* resolve_module(size_t depth) { |
64
|
402
|
|
|
|
|
|
Stash stash; |
65
|
201
|
100
|
|
|
|
|
if (depth == 0) { |
66
|
189
|
50
|
|
|
|
|
stash = CopSTASH(PL_curcop); |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
else { |
69
|
12
|
|
|
|
|
|
const PERL_CONTEXT *dbcx = nullptr; |
70
|
12
|
50
|
|
|
|
|
const PERL_CONTEXT *cx = caller_cx(depth, &dbcx); |
71
|
12
|
50
|
|
|
|
|
if (cx) { |
72
|
12
|
50
|
|
|
|
|
if ((CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT)) { |
|
|
0
|
|
|
|
|
|
73
|
|
|
|
|
|
|
#ifdef CvHASGV |
74
|
12
|
|
|
|
|
|
bool has_gv = CvHASGV(dbcx->blk_sub.cv); |
75
|
|
|
|
|
|
|
#else |
76
|
|
|
|
|
|
|
GV * const cvgv = CvGV(dbcx->blk_sub.cv); |
77
|
|
|
|
|
|
|
/* So is ccstack[dbcxix]. */ |
78
|
|
|
|
|
|
|
bool has_gv = (cvgv && isGV(cvgv)); |
79
|
|
|
|
|
|
|
#endif |
80
|
12
|
50
|
|
|
|
|
if (has_gv) { |
81
|
24
|
50
|
|
|
|
|
xs::Sub sub(dbcx->blk_sub.cv); |
82
|
12
|
50
|
|
|
|
|
stash = sub.glob().effective_stash(); |
|
|
50
|
|
|
|
|
|
83
|
12
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
12
|
0
|
|
|
|
|
else stash = CopSTASH(cx->blk_oldcop); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
// fallback |
89
|
201
|
50
|
|
|
|
|
if (!stash) return &::panda_log_module; |
90
|
|
|
|
|
|
|
|
91
|
201
|
50
|
|
|
|
|
return get_module_by_namespace(stash); |
|
|
50
|
|
|
|
|
|
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
template |
96
|
103
|
|
|
|
|
|
inline static OP* pp_maybe_skip(SkipPredicate&& p) { |
97
|
103
|
|
|
|
|
|
bool skip = true; |
98
|
|
|
|
|
|
|
try { |
99
|
103
|
0
|
|
|
|
|
skip = p(); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
100
|
3
|
|
|
|
|
|
} catch (panda::string& ex) { |
101
|
3
|
0
|
|
|
|
|
croak_sv(newSVpvn_flags(ex.c_str(), ex.length(), SVf_UTF8 | SVs_TEMP)); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
102
|
|
|
|
|
|
|
} |
103
|
100
|
0
|
|
|
|
|
if (skip) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
104
|
27
|
|
|
|
|
|
OP* cur_op = PL_op; |
105
|
89
|
0
|
|
|
|
|
while (OpHAS_SIBLING(cur_op)) { cur_op = OpSIBLING(cur_op); } |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
106
|
81
|
0
|
|
|
|
|
while (cur_op->op_type != OP_ENTERSUB) { cur_op = cur_op->op_next; } |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
107
|
27
|
|
|
|
|
|
return cur_op->op_next; |
108
|
|
|
|
|
|
|
} else { |
109
|
103
|
0
|
|
|
|
|
return PL_ppaddr[PL_op->op_type](aTHX); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
103
|
|
|
|
|
|
static bool final_check(Level level, SV* mod_sv) { |
114
|
103
|
|
|
|
|
|
const Module* module = nullptr; |
115
|
103
|
100
|
|
|
|
|
if (mod_sv) { |
116
|
66
|
50
|
|
|
|
|
if (mod_sv && SvROK(mod_sv)) { |
|
|
100
|
|
|
|
|
|
117
|
42
|
|
|
|
|
|
auto ref = SvRV(mod_sv); |
118
|
42
|
|
|
|
|
|
bool ok = has_module(ref); |
119
|
42
|
50
|
|
|
|
|
if (ok) { |
120
|
66
|
|
|
|
|
|
module = xs::in(ref); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
} |
124
|
100
|
100
|
|
|
|
|
if (!module) module = resolve_module(0); |
125
|
100
|
|
|
|
|
|
return module->level() > level; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
namespace access { |
129
|
|
|
|
|
|
|
|
130
|
38
|
|
|
|
|
|
SV* constsv(const OP* op) { |
131
|
38
|
50
|
|
|
|
|
if (op->op_type == OP_CONST) return cSVOPx_sv(op); |
132
|
0
|
|
|
|
|
|
return nullptr; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
69
|
|
|
|
|
|
SV* padsv(const OP* op) { |
136
|
69
|
50
|
|
|
|
|
if (op->op_type == OP_PADSV) return PAD_SVl(op->op_targ); |
137
|
0
|
|
|
|
|
|
return nullptr; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
12
|
|
|
|
|
|
SV* rv2sv(const OP* op) { |
141
|
12
|
50
|
|
|
|
|
if (OP_TYPE_IS_OR_WAS(op, OP_RV2SV)) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
142
|
12
|
|
|
|
|
|
auto gvop = cUNOPx(op)->op_first; |
143
|
12
|
50
|
|
|
|
|
if (gvop->op_type == OP_GVSV) { |
144
|
12
|
|
|
|
|
|
auto gv = cGVOPx_gv(gvop); |
145
|
12
|
50
|
|
|
|
|
if (SvTYPE(gv) == SVt_PVGV) { |
146
|
12
|
|
|
|
|
|
return GvSV(gv); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
} |
150
|
0
|
|
|
|
|
|
return nullptr; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
namespace with_level { |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
template struct AutoModule { |
159
|
15
|
|
|
|
|
|
static OP* pp(pTHX) { |
160
|
30
|
|
|
|
|
|
auto check = [&]() { return final_check(level, nullptr); }; |
161
|
15
|
0
|
|
|
|
|
return pp_maybe_skip(check); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
}; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
template struct PADSV { |
166
|
27
|
|
|
|
|
|
static OP* pp(pTHX) { |
167
|
27
|
|
|
|
|
|
auto check = [&]() { |
168
|
27
|
0
|
|
|
|
|
auto sv = access::padsv(OpSIBLING(PL_op)); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
169
|
27
|
|
|
|
|
|
return final_check(level, sv); |
170
|
|
|
|
|
|
|
}; |
171
|
27
|
0
|
|
|
|
|
return pp_maybe_skip(check); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
}; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
template struct RV2SV { |
176
|
8
|
|
|
|
|
|
static OP* pp(pTHX) { |
177
|
8
|
|
|
|
|
|
auto check = [&]() { |
178
|
8
|
|
|
|
|
|
bool skip = false; |
179
|
8
|
0
|
|
|
|
|
auto sv = access::rv2sv(OpSIBLING(PL_op)); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
180
|
8
|
0
|
|
|
|
|
if (sv) skip = final_check(level, sv); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
181
|
8
|
|
|
|
|
|
return skip; |
182
|
|
|
|
|
|
|
}; |
183
|
8
|
0
|
|
|
|
|
return pp_maybe_skip(check); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
}; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
template class Backend> |
189
|
45
|
|
|
|
|
|
backend_t apply(Level level) { |
190
|
45
|
|
|
|
|
|
switch (level) { |
191
|
2
|
|
|
|
|
|
case Level::VerboseDebug : return &Backend::pp; |
192
|
11
|
|
|
|
|
|
case Level::Debug : return &Backend::pp; |
193
|
1
|
|
|
|
|
|
case Level::Info : return &Backend::pp; |
194
|
1
|
|
|
|
|
|
case Level::Notice : return &Backend::pp; |
195
|
14
|
|
|
|
|
|
case Level::Warning : return &Backend::pp; |
196
|
13
|
|
|
|
|
|
case Level::Error : return &Backend::pp; |
197
|
1
|
|
|
|
|
|
case Level::Critical : return &Backend::pp; |
198
|
1
|
|
|
|
|
|
case Level::Alert : return &Backend::pp; |
199
|
1
|
|
|
|
|
|
case Level::Emergency : return &Backend::pp; |
200
|
|
|
|
|
|
|
} |
201
|
0
|
|
|
|
|
|
std::abort(); |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
namespace fetch_level { |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
enum class LevelAccess { op_const, op_padsv, op_rv2sv }; |
209
|
|
|
|
|
|
|
enum class ModuleAccess { op_const, op_padsv, op_rv2sv, deduce }; |
210
|
|
|
|
|
|
|
using LevelOption = panda::optional; |
211
|
|
|
|
|
|
|
|
212
|
53
|
|
|
|
|
|
static inline LevelOption sv2level (SV* sv) { |
213
|
|
|
|
|
|
|
using namespace panda::log; |
214
|
53
|
50
|
|
|
|
|
if (sv) { |
215
|
53
|
100
|
|
|
|
|
int l = SvIV(sv); |
216
|
53
|
50
|
|
|
|
|
if (l >= (int)Level::VerboseDebug && l <= (int)Level::Emergency) return LevelOption((Level)l); |
|
|
50
|
|
|
|
|
|
217
|
|
|
|
|
|
|
} |
218
|
0
|
|
|
|
|
|
return LevelOption{}; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
template struct GetLevel; |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
template<> struct GetLevel { |
224
|
18
|
|
|
|
|
|
static LevelOption get (OP* op) { |
225
|
18
|
|
|
|
|
|
return sv2level(access::constsv(op)); |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
}; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
template<> struct GetLevel { |
230
|
31
|
|
|
|
|
|
static LevelOption get (OP* op) { |
231
|
31
|
|
|
|
|
|
return sv2level(access::padsv(op)); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
}; |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
template<> struct GetLevel { |
236
|
4
|
|
|
|
|
|
static LevelOption get (OP* op) { |
237
|
4
|
|
|
|
|
|
return sv2level(access::rv2sv(op)); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
}; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
template struct GetModule; |
242
|
|
|
|
|
|
|
template<> struct GetModule { |
243
|
40
|
50
|
|
|
|
|
static SV* get (OP* op_prev) { return access::constsv(OpSIBLING(op_prev)); } |
244
|
|
|
|
|
|
|
}; |
245
|
|
|
|
|
|
|
template<> struct GetModule { |
246
|
22
|
50
|
|
|
|
|
static SV* get (OP* op_prev) { return access::padsv(OpSIBLING(op_prev)); } |
247
|
|
|
|
|
|
|
}; |
248
|
|
|
|
|
|
|
template<> struct GetModule { |
249
|
0
|
0
|
|
|
|
|
static SV* get (OP* op_prev) { return access::rv2sv(OpSIBLING(op_prev)); } |
250
|
|
|
|
|
|
|
}; |
251
|
|
|
|
|
|
|
template<> struct GetModule { |
252
|
44
|
|
|
|
|
|
static SV* get (OP*) { return nullptr; } |
253
|
|
|
|
|
|
|
}; |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
template |
257
|
|
|
|
|
|
|
struct OpAccessor { |
258
|
53
|
|
|
|
|
|
static OP* pp (pTHX) { |
259
|
53
|
|
|
|
|
|
auto check = [&]() { |
260
|
53
|
50
|
|
|
|
|
auto op = OpSIBLING(PL_op); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
261
|
53
|
|
|
|
|
|
bool skip = false; |
262
|
106
|
50
|
|
|
|
|
auto level_option = GetLevel::get(op); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
263
|
53
|
50
|
|
|
|
|
if (level_option) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
264
|
53
|
0
|
|
|
|
|
auto sv_module = GetModule::get(op); |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
265
|
53
|
50
|
|
|
|
|
skip = final_check(level_option.value(), sv_module); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
266
|
|
|
|
|
|
|
} |
267
|
50
|
|
|
|
|
|
return skip; |
268
|
|
|
|
|
|
|
}; |
269
|
53
|
50
|
|
|
|
|
return pp_maybe_skip(check); |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
}; |
272
|
|
|
|
|
|
|
|
273
|
31
|
|
|
|
|
|
backend_t compose (LevelAccess level_access, ModuleAccess module_access) { |
274
|
31
|
|
|
|
|
|
switch (module_access) { |
275
|
|
|
|
|
|
|
case ModuleAccess::op_const: { |
276
|
13
|
|
|
|
|
|
switch (level_access) { |
277
|
11
|
|
|
|
|
|
case LevelAccess::op_const: return &OpAccessor::pp; |
278
|
2
|
|
|
|
|
|
case LevelAccess::op_padsv: return &OpAccessor::pp; |
279
|
0
|
|
|
|
|
|
case LevelAccess::op_rv2sv: return &OpAccessor::pp; |
280
|
0
|
|
|
|
|
|
} break; } |
281
|
|
|
|
|
|
|
case ModuleAccess::op_padsv: { |
282
|
5
|
|
|
|
|
|
switch (level_access) { |
283
|
4
|
|
|
|
|
|
case LevelAccess::op_const: return &OpAccessor::pp; |
284
|
1
|
|
|
|
|
|
case LevelAccess::op_padsv: return &OpAccessor::pp; |
285
|
0
|
|
|
|
|
|
case LevelAccess::op_rv2sv: return &OpAccessor::pp; |
286
|
0
|
|
|
|
|
|
} break; } |
287
|
|
|
|
|
|
|
case ModuleAccess::op_rv2sv: { |
288
|
0
|
|
|
|
|
|
switch (level_access) { |
289
|
0
|
|
|
|
|
|
case LevelAccess::op_const: return &OpAccessor::pp; |
290
|
0
|
|
|
|
|
|
case LevelAccess::op_padsv: return &OpAccessor::pp; |
291
|
0
|
|
|
|
|
|
case LevelAccess::op_rv2sv: return &OpAccessor::pp; |
292
|
0
|
|
|
|
|
|
} break; } |
293
|
|
|
|
|
|
|
case ModuleAccess::deduce: { |
294
|
13
|
|
|
|
|
|
switch (level_access) { |
295
|
7
|
|
|
|
|
|
case LevelAccess::op_const: return &OpAccessor::pp; |
296
|
4
|
|
|
|
|
|
case LevelAccess::op_padsv: return &OpAccessor::pp; |
297
|
2
|
|
|
|
|
|
case LevelAccess::op_rv2sv: return &OpAccessor::pp; |
298
|
0
|
|
|
|
|
|
} break; } |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
assert(0 && "should not happen"); |
301
|
0
|
|
|
|
|
|
return nullptr; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
85
|
|
|
|
|
|
static void optimize (size_t module_pos, Optimizer&& optimizer) { |
307
|
85
|
|
|
|
|
|
OP* op = PL_op; |
308
|
85
|
|
|
|
|
|
bool already_optimized = op->op_spare & 1; |
309
|
170
|
50
|
|
|
|
|
if (already_optimized) return; |
310
|
|
|
|
|
|
|
/* it does not matter whether successful optimization was applied or not. |
311
|
|
|
|
|
|
|
* in any case it will not be attempted to be applied again */ |
312
|
85
|
|
|
|
|
|
op->op_spare |= 1; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
/* can be goto, no optimization */ |
315
|
85
|
100
|
|
|
|
|
if (op->op_type != OP_ENTERSUB) return; |
316
|
|
|
|
|
|
|
|
317
|
83
|
|
|
|
|
|
OP* args_op = cUNOPx(op)->op_first; |
318
|
83
|
|
|
|
|
|
bool ok = true; |
319
|
166
|
50
|
|
|
|
|
while(ok && args_op->op_type == OP_NULL) { |
|
|
100
|
|
|
|
|
|
320
|
83
|
|
|
|
|
|
auto klass = PL_opargs[(args_op->op_targ)] & OA_CLASS_MASK; |
321
|
83
|
|
|
|
|
|
switch (klass) { |
322
|
0
|
|
|
|
|
|
case OA_UNOP: args_op = cUNOPx(args_op)->op_first; break; |
323
|
83
|
|
|
|
|
|
case OA_LISTOP: args_op = cLISTOPx(args_op)->op_first; break; |
324
|
0
|
|
|
|
|
|
default: ok = false; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
83
|
|
|
|
|
|
auto type = args_op->op_type; |
329
|
|
|
|
|
|
|
/* we don't know what it is, no optimization is possible */ |
330
|
83
|
100
|
|
|
|
|
if ((type != OP_PUSHMARK) && (type != OP_PADRANGE)) return; |
|
|
50
|
|
|
|
|
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
/* somebody already optimized arg op, skip */ |
333
|
83
|
50
|
|
|
|
|
if ((args_op->op_ppaddr != PL_ppaddr[type]) || (args_op->op_spare & 1)) return; |
|
|
50
|
|
|
|
|
|
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
/* no idea how this can be */ |
336
|
83
|
50
|
|
|
|
|
if (!OpHAS_SIBLING(args_op)) return; |
337
|
|
|
|
|
|
|
|
338
|
166
|
|
|
|
|
|
Args args; |
339
|
83
|
50
|
|
|
|
|
OP *cur_op = OpSIBLING(args_op); |
340
|
184
|
100
|
|
|
|
|
while(OpHAS_SIBLING(cur_op) && (args.size() < module_pos) && !OP_TYPE_IS_OR_WAS(cur_op,OP_RV2CV)){ |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
341
|
101
|
100
|
|
|
|
|
args.push_back(cur_op->op_type == OP_NULL ? cur_op->op_targ : cur_op->op_type); |
|
|
50
|
|
|
|
|
|
342
|
101
|
50
|
|
|
|
|
cur_op = OpSIBLING(cur_op); |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
96
|
100
|
|
|
|
|
while((args.size() < module_pos)) args.push_back(OP_NA); |
|
|
50
|
|
|
|
|
|
346
|
83
|
50
|
|
|
|
|
backend_t backend = optimizer(args); |
347
|
83
|
100
|
|
|
|
|
if (backend != nullptr) { |
348
|
76
|
|
|
|
|
|
args_op->op_ppaddr = backend; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
31
|
|
|
|
|
|
void optimize () { |
353
|
31
|
|
|
|
|
|
auto optimizer = [] (const Args& args) -> backend_t { |
354
|
|
|
|
|
|
|
using namespace fetch_level; |
355
|
|
|
|
|
|
|
LevelAccess level_access; |
356
|
31
|
|
|
|
|
|
switch (args[0]) { |
357
|
22
|
|
|
|
|
|
case OP_CONST: level_access = LevelAccess::op_const; break; |
358
|
7
|
|
|
|
|
|
case OP_PADSV: level_access = LevelAccess::op_padsv; break; |
359
|
2
|
|
|
|
|
|
case OP_RV2SV: level_access = LevelAccess::op_rv2sv; break; |
360
|
0
|
|
|
|
|
|
default: return nullptr; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
ModuleAccess module_access; |
364
|
31
|
|
|
|
|
|
switch (args[1]) { |
365
|
13
|
|
|
|
|
|
case OP_CONST: module_access = ModuleAccess::op_const; break; |
366
|
5
|
|
|
|
|
|
case OP_PADSV: module_access = ModuleAccess::op_padsv; break; |
367
|
0
|
|
|
|
|
|
case OP_RV2SV: module_access = ModuleAccess::op_rv2sv; break; |
368
|
13
|
|
|
|
|
|
default: module_access = ModuleAccess::deduce; break; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
31
|
|
|
|
|
|
return compose(level_access, module_access); |
372
|
|
|
|
|
|
|
}; |
373
|
31
|
50
|
|
|
|
|
optimize(2, optimizer); |
|
|
50
|
|
|
|
|
|
374
|
31
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
54
|
|
|
|
|
|
void optimize (panda::log::Level level) { |
378
|
52
|
|
|
|
|
|
auto optimizer = [level] (const Args& args) -> backend_t { |
379
|
|
|
|
|
|
|
using namespace with_level; |
380
|
52
|
|
|
|
|
|
switch (args.front()) { |
381
|
5
|
|
|
|
|
|
case OP_NA : return apply(level); |
382
|
26
|
|
|
|
|
|
case OP_CONST: return apply(level); |
383
|
10
|
|
|
|
|
|
case OP_PADSV: return apply(level); |
384
|
4
|
|
|
|
|
|
case OP_RV2SV: return apply(level); |
385
|
|
|
|
|
|
|
} |
386
|
7
|
|
|
|
|
|
return nullptr; |
387
|
54
|
|
|
|
|
|
}; |
388
|
54
|
50
|
|
|
|
|
optimize(1, optimizer); |
|
|
50
|
|
|
|
|
|
389
|
54
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
}} |