File Coverage

duk.xs
Criterion Covered Total %
statement 114 125 91.2
branch 56 132 42.4
condition n/a
subroutine n/a
pod n/a
total 170 257 66.1


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT /* we want efficiency */
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6              
7             /*
8             * Duktape is an embeddable Javascript engine, with a focus on portability and
9             * compact footprint.
10             *
11             * http://duktape.org/index.html
12             */
13             #include "pl_duk.h"
14             #include "pl_stats.h"
15             #include "pl_module.h"
16             #include "pl_eventloop.h"
17             #include "pl_console.h"
18             #include "pl_native.h"
19             #include "pl_inlined.h"
20             #include "pl_sandbox.h"
21             #include "pl_util.h"
22              
23             #define MAX_MEMORY_MINIMUM (128 * 1024) /* 128 KB */
24             #define MAX_TIMEOUT_MINIMUM (500000) /* 500_000 us = 500 ms = 0.5 s */
25              
26             #define TIMEOUT_RESET(duk) \
27             do { \
28             if (duk->max_timeout_us > 0) { \
29             duk->eval_start_us = now_us(); \
30             } \
31             } while (0) \
32              
33 0           static void duk_fatal_error_handler(void* udata, const char* msg)
34             {
35             dTHX;
36              
37             /* Duk* duk = (Duk*) udata; */
38             UNUSED_ARG(udata);
39              
40 0 0         PerlIO_printf(PerlIO_stderr(), "duktape fatal error, aborting: %s\n", msg ? msg : "*NONE*");
41 0           abort();
42             }
43              
44 269           static void set_up(Duk* duk)
45             {
46 269 50         if (duk->inited) {
47 0           return;
48             }
49 269           duk->inited = 1;
50              
51 269           duk->ctx = duk_create_heap(pl_sandbox_alloc, pl_sandbox_realloc, pl_sandbox_free, duk, duk_fatal_error_handler);
52 269 50         if (!duk->ctx) {
53 0           croak("Could not create duk heap\n");
54             }
55              
56 269 100         TIMEOUT_RESET(duk);
57              
58             /* register a bunch of native functions */
59 269           pl_register_native_functions(duk);
60              
61             /* initialize module handling functions */
62 269           pl_register_module_functions(duk);
63              
64             /* register event loop dispatcher */
65 269           pl_register_eventloop(duk);
66              
67             /* inline a bunch of JS functions */
68 269           pl_register_inlined_functions(duk);
69              
70             /* initialize console object */
71 269           pl_console_init(duk);
72             }
73              
74 269           static void tear_down(Duk* duk)
75             {
76 269 50         if (!duk->inited) {
77 0           return;
78             }
79 269           duk->inited = 0;
80              
81 269           duk_destroy_heap(duk->ctx);
82             }
83              
84 155           static Duk* create_duktape_object(pTHX_ HV* opt)
85             {
86 155           Duk* duk = (Duk*) malloc(sizeof(Duk));
87 155           memset(duk, 0, sizeof(Duk));
88              
89 155           duk->pagesize_bytes = getpagesize();
90              
91 155           duk->stats = newHV();
92 155           duk->msgs = newHV();
93              
94 155 100         if (opt) {
95 6           hv_iterinit(opt);
96             while (1) {
97 12           SV* value = 0;
98 12           I32 klen = 0;
99 12           char* kstr = 0;
100 12           HE* entry = hv_iternext(opt);
101 12 100         if (!entry) {
102 6           break; /* no more hash keys */
103             }
104 6           kstr = hv_iterkey(entry, &klen);
105 6 50         if (!kstr || klen < 0) {
    50          
106 0           continue; /* invalid key */
107             }
108 6           value = hv_iterval(opt, entry);
109 6 50         if (!value) {
110 0           continue; /* invalid value */
111             }
112 6 100         if (memcmp(kstr, DUK_OPT_NAME_GATHER_STATS, klen) == 0) {
113 2 50         duk->flags |= SvTRUE(value) ? DUK_OPT_FLAG_GATHER_STATS : 0;
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
114 2           continue;
115             }
116 4 100         if (memcmp(kstr, DUK_OPT_NAME_SAVE_MESSAGES, klen) == 0) {
117 2 50         duk->flags |= SvTRUE(value) ? DUK_OPT_FLAG_SAVE_MESSAGES : 0;
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
118 2           continue;
119             }
120 2 100         if (memcmp(kstr, DUK_OPT_NAME_MAX_MEMORY_BYTES, klen) == 0) {
121 1 50         size_t param = SvIV(value);
122 1           duk->max_allocated_bytes = param > MAX_MEMORY_MINIMUM ? param : MAX_MEMORY_MINIMUM;
123 1           continue;
124             }
125 1 50         if (memcmp(kstr, DUK_OPT_NAME_MAX_TIMEOUT_US, klen) == 0) {
126 1 50         double param = SvIV(value);
127 1 50         duk->max_timeout_us = param > MAX_TIMEOUT_MINIMUM ? param : MAX_TIMEOUT_MINIMUM;
128 1           continue;
129             }
130 0           croak("Unknown option %*.*s\n", (int) klen, (int) klen, kstr);
131 6           }
132             }
133              
134 155           set_up(duk);
135 155           return duk;
136             }
137              
138 155           static int session_dtor(pTHX_ SV* sv, MAGIC* mg)
139             {
140 155           Duk* duk = (Duk*) mg->mg_ptr;
141             UNUSED_ARG(sv);
142 155           tear_down(duk);
143 155           return 0;
144             }
145              
146             static MGVTBL session_magic_vtbl = { .svt_free = session_dtor };
147              
148             MODULE = JavaScript::Duktape::XS PACKAGE = JavaScript::Duktape::XS
149             PROTOTYPES: DISABLE
150              
151             #################################################################
152              
153             Duk*
154             new(char* CLASS, HV* opt = NULL)
155             CODE:
156             UNUSED_ARG(opt);
157 155           RETVAL = create_duktape_object(aTHX_ opt);
158             OUTPUT: RETVAL
159              
160             void
161             reset(Duk* duk)
162             PPCODE:
163 114           tear_down(duk);
164 114           set_up(duk);
165              
166             HV*
167             get_stats(Duk* duk)
168             CODE:
169 9           RETVAL = duk->stats;
170             OUTPUT: RETVAL
171              
172             void
173             reset_stats(Duk* duk)
174             PPCODE:
175 0           duk->stats = newHV();
176              
177             HV*
178             get_msgs(Duk* duk)
179             CODE:
180 1           RETVAL = duk->msgs;
181             OUTPUT: RETVAL
182              
183             void
184             reset_msgs(Duk* duk)
185             PPCODE:
186 0           duk->msgs = newHV();
187              
188             SV*
189             get(Duk* duk, const char* name)
190             PREINIT:
191 1001093           duk_context* ctx = 0;
192             Stats stats;
193             CODE:
194 1001093 50         TIMEOUT_RESET(duk);
195 1001093           ctx = duk->ctx;
196 1001093           pl_stats_start(aTHX_ duk, &stats);
197 1001093           RETVAL = pl_get_global_or_property(aTHX_ ctx, name);
198 1001093           pl_stats_stop(aTHX_ duk, &stats, "get");
199             OUTPUT: RETVAL
200              
201             SV*
202             exists(Duk* duk, const char* name)
203             PREINIT:
204 60           duk_context* ctx = 0;
205             Stats stats;
206             CODE:
207 60 50         TIMEOUT_RESET(duk);
208 60           ctx = duk->ctx;
209 60           pl_stats_start(aTHX_ duk, &stats);
210 60           RETVAL = pl_exists_global_or_property(aTHX_ ctx, name);
211 60           pl_stats_stop(aTHX_ duk, &stats, "exists");
212             OUTPUT: RETVAL
213              
214             SV*
215             typeof(Duk* duk, const char* name)
216             PREINIT:
217 20           duk_context* ctx = 0;
218             Stats stats;
219             CODE:
220 20 50         TIMEOUT_RESET(duk);
221 20           ctx = duk->ctx;
222 20           pl_stats_start(aTHX_ duk, &stats);
223 20           RETVAL = pl_typeof_global_or_property(aTHX_ ctx, name);
224 20           pl_stats_stop(aTHX_ duk, &stats, "typeof");
225             OUTPUT: RETVAL
226              
227             SV*
228             instanceof(Duk* duk, const char* object, const char* class)
229             PREINIT:
230 12           duk_context* ctx = 0;
231             Stats stats;
232             CODE:
233 12 50         TIMEOUT_RESET(duk);
234 12           ctx = duk->ctx;
235 12           pl_stats_start(aTHX_ duk, &stats);
236 12           RETVAL = pl_instanceof_global_or_property(aTHX_ ctx, object, class);
237 12           pl_stats_stop(aTHX_ duk, &stats, "instanceof");
238             OUTPUT: RETVAL
239              
240             int
241             set(Duk* duk, const char* name, SV* value)
242             PREINIT:
243 2111           duk_context* ctx = 0;
244             Stats stats;
245             CODE:
246 2111 50         TIMEOUT_RESET(duk);
247 2111           ctx = duk->ctx;
248 2111           pl_stats_start(aTHX_ duk, &stats);
249 2111           RETVAL = pl_set_global_or_property(aTHX_ ctx, name, value);
250 2111           pl_stats_stop(aTHX_ duk, &stats, "set");
251             OUTPUT: RETVAL
252              
253             int
254             remove(Duk* duk, const char* name)
255             PREINIT:
256 8           duk_context* ctx = 0;
257             Stats stats;
258             CODE:
259 8 50         TIMEOUT_RESET(duk);
260 8           ctx = duk->ctx;
261 8           pl_stats_start(aTHX_ duk, &stats);
262 8           RETVAL = pl_del_global_or_property(aTHX_ ctx, name);
263 8           pl_stats_stop(aTHX_ duk, &stats, "remove");
264             OUTPUT: RETVAL
265              
266             SV*
267             eval(Duk* duk, const char* js, const char* file = 0)
268             CODE:
269 2000090 100         TIMEOUT_RESET(duk);
270 2000090           RETVAL = pl_eval(aTHX_ duk, js, file);
271             OUTPUT: RETVAL
272              
273             SV*
274             dispatch_function_in_event_loop(Duk* duk, const char* func)
275             PREINIT:
276             Stats stats;
277             CODE:
278 3 50         TIMEOUT_RESET(duk);
279 3           pl_stats_start(aTHX_ duk, &stats);
280 3           RETVAL = newSViv(pl_run_function_in_event_loop(duk, func));
281 3           pl_stats_stop(aTHX_ duk, &stats, "dispatch");
282             OUTPUT: RETVAL
283              
284             HV*
285             get_version_info(Duk* duk)
286             CODE:
287 1 50         if (!duk->version) {
288 1           duk->version = pl_get_version_info(aTHX);
289             }
290 1           RETVAL = duk->version;
291             OUTPUT: RETVAL
292              
293             SV*
294             run_gc(Duk* duk)
295             PREINIT:
296             Stats stats;
297             CODE:
298 1 50         TIMEOUT_RESET(duk);
299 1           pl_stats_start(aTHX_ duk, &stats);
300 1           RETVAL = newSVnv(pl_run_gc(duk));
301 1           pl_stats_stop(aTHX_ duk, &stats, "run_gc");
302             OUTPUT: RETVAL
303              
304             SV*
305             global_objects(Duk* duk)
306             PREINIT:
307 18           duk_context* ctx = 0;
308             Stats stats;
309             CODE:
310 18 50         TIMEOUT_RESET(duk);
311 18           ctx = duk->ctx;
312 18           pl_stats_start(aTHX_ duk, &stats);
313 18           RETVAL = pl_global_objects(aTHX_ ctx);
314 18           pl_stats_stop(aTHX_ duk, &stats, "global_objects");
315             OUTPUT: RETVAL