1 /* Copyright (C) 2006 The PARI group.
2
3 This file is part of the PARI package.
4
5 PARI/GP is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 2 of the License, or (at your option) any later
8 version. It is distributed in the hope that it will be useful, but WITHOUT
9 ANY WARRANTY WHATSOEVER.
10
11 Check the License for details. You should have received a copy of it, along
12 with the package; see the file 'COPYING'. If not, write to the Free Software
13 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
14
15 #include "pari.h"
16 #include "paripriv.h"
17 #include "anal.h"
18 #include "opcode.h"
19
20 /********************************************************************/
21 /* */
22 /* break/next/return handling */
23 /* */
24 /********************************************************************/
25
26 static THREAD long br_status, br_count;
27 static THREAD GEN br_res;
28
29 long
loop_break(void)30 loop_break(void)
31 {
32 switch(br_status)
33 {
34 case br_MULTINEXT :
35 if (! --br_count) br_status = br_NEXT;
36 return 1;
37 case br_BREAK : if (! --br_count) br_status = br_NONE; /* fall through */
38 case br_RETURN: return 1;
39 case br_NEXT: br_status = br_NONE; /* fall through */
40 }
41 return 0;
42 }
43
44 static void
reset_break(void)45 reset_break(void)
46 {
47 br_status = br_NONE;
48 if (br_res) { gunclone_deep(br_res); br_res = NULL; }
49 }
50
51 GEN
return0(GEN x)52 return0(GEN x)
53 {
54 GEN y = br_res;
55 br_res = (x && x != gnil)? gcloneref(x): NULL;
56 guncloneNULL_deep(y);
57 br_status = br_RETURN; return NULL;
58 }
59
60 GEN
next0(long n)61 next0(long n)
62 {
63 if (n < 1) pari_err_DOMAIN("next", "n", "<", gen_1, stoi(n));
64 if (n == 1) br_status = br_NEXT;
65 else
66 {
67 br_count = n-1;
68 br_status = br_MULTINEXT;
69 }
70 return NULL;
71 }
72
73 GEN
break0(long n)74 break0(long n)
75 {
76 if (n < 1) pari_err_DOMAIN("break", "n", "<", gen_1, stoi(n));
77 br_count = n;
78 br_status = br_BREAK; return NULL;
79 }
80
81 /*******************************************************************/
82 /* */
83 /* VARIABLES */
84 /* */
85 /*******************************************************************/
86
87 /* As a rule, ep->value is a clone (COPY). push_val and pop_val are private
88 * functions for use in sumiter: we want a temporary ep->value, which is NOT
89 * a clone (PUSH), to avoid unnecessary copies. */
90
91 enum {PUSH_VAL = 0, COPY_VAL = 1, DEFAULT_VAL = 2, REF_VAL = 3};
92
93 /* ep->args is the stack of old values (INITIAL if initial value, from
94 * installep) */
95 typedef struct var_cell {
96 struct var_cell *prev; /* cell attached to previous value on stack */
97 GEN value; /* last value (not including current one, in ep->value) */
98 char flag; /* status of _current_ ep->value: PUSH or COPY ? */
99 long valence; /* valence of entree* attached to 'value', to be restored
100 * by pop_val */
101 } var_cell;
102 #define INITIAL NULL
103
104 /* Push x on value stack attached to ep. */
105 static void
new_val_cell(entree * ep,GEN x,char flag)106 new_val_cell(entree *ep, GEN x, char flag)
107 {
108 var_cell *v = (var_cell*) pari_malloc(sizeof(var_cell));
109 v->value = (GEN)ep->value;
110 v->prev = (var_cell*) ep->pvalue;
111 v->flag = flag;
112 v->valence= ep->valence;
113
114 /* beware: f(p) = Nv = 0
115 * Nv = p; f(Nv) --> this call would destroy p [ isclone ] */
116 ep->value = (flag == COPY_VAL)? gclone(x):
117 (x && isclone(x))? gcopy(x): x;
118 /* Do this last. In case the clone is <C-C>'ed before completion ! */
119 ep->pvalue= (char*)v;
120 ep->valence=EpVAR;
121 }
122
123 /* kill ep->value and replace by preceding one, poped from value stack */
124 static void
pop_val(entree * ep)125 pop_val(entree *ep)
126 {
127 var_cell *v = (var_cell*) ep->pvalue;
128 if (v != INITIAL)
129 {
130 GEN old_val = (GEN) ep->value; /* protect against SIGINT */
131 ep->value = v->value;
132 if (v->flag == COPY_VAL) gunclone_deep(old_val);
133 ep->pvalue = (char*) v->prev;
134 ep->valence=v->valence;
135 pari_free((void*)v);
136 }
137 }
138
139 void
freeep(entree * ep)140 freeep(entree *ep)
141 {
142 if (EpSTATIC(ep)) return; /* gp function loaded at init time */
143 if (ep->help) {pari_free((void*)ep->help); ep->help=NULL;}
144 if (ep->code) {pari_free((void*)ep->code); ep->code=NULL;}
145 switch(EpVALENCE(ep))
146 {
147 case EpVAR:
148 while (ep->pvalue!=INITIAL) pop_val(ep);
149 break;
150 case EpALIAS:
151 killblock((GEN)ep->value); ep->value=NULL; break;
152 }
153 }
154
155 INLINE void
pushvalue(entree * ep,GEN x)156 pushvalue(entree *ep, GEN x) {
157 new_val_cell(ep, x, COPY_VAL);
158 }
159
160 INLINE void
zerovalue(entree * ep)161 zerovalue(entree *ep)
162 {
163 var_cell *v = (var_cell*) pari_malloc(sizeof(var_cell));
164 v->value = (GEN)ep->value;
165 v->prev = (var_cell*) ep->pvalue;
166 v->flag = PUSH_VAL;
167 v->valence= ep->valence;
168 ep->value = gen_0;
169 ep->pvalue= (char*)v;
170 ep->valence=EpVAR;
171 }
172
173 /* as above IF ep->value was PUSHed, or was created after block number 'loc'
174 return 0 if not deleted, 1 otherwise [for recover()] */
175 int
pop_val_if_newer(entree * ep,long loc)176 pop_val_if_newer(entree *ep, long loc)
177 {
178 var_cell *v = (var_cell*) ep->pvalue;
179
180 if (v == INITIAL) return 0;
181 if (v->flag == COPY_VAL && !pop_entree_block(ep, loc)) return 0;
182 ep->value = v->value;
183 ep->pvalue= (char*) v->prev;
184 ep->valence=v->valence;
185 pari_free((void*)v); return 1;
186 }
187
188 /* set new value of ep directly to val (COPY), do not save last value unless
189 * it's INITIAL. */
190 void
changevalue(entree * ep,GEN x)191 changevalue(entree *ep, GEN x)
192 {
193 var_cell *v = (var_cell*) ep->pvalue;
194 if (v == INITIAL) new_val_cell(ep, x, COPY_VAL);
195 else
196 {
197 GEN old_val = (GEN) ep->value; /* beware: gunclone_deep may destroy old x */
198 ep->value = (void *) gclone(x);
199 if (v->flag == COPY_VAL) gunclone_deep(old_val); else v->flag = COPY_VAL;
200 }
201 }
202
203 INLINE GEN
copyvalue(entree * ep)204 copyvalue(entree *ep)
205 {
206 var_cell *v = (var_cell*) ep->pvalue;
207 if (v && v->flag != COPY_VAL)
208 {
209 ep->value = (void*) gclone((GEN)ep->value);
210 v->flag = COPY_VAL;
211 }
212 return (GEN) ep->value;
213 }
214
215 INLINE void
err_var(GEN x)216 err_var(GEN x) { pari_err_TYPE("evaluator [variable name expected]", x); }
217
218 enum chk_VALUE { chk_ERROR, chk_NOCREATE, chk_CREATE };
219
220 INLINE void
checkvalue(entree * ep,enum chk_VALUE flag)221 checkvalue(entree *ep, enum chk_VALUE flag)
222 {
223 if (mt_is_thread())
224 pari_err(e_MISC,"mt: attempt to change exported variable '%s'",ep->name);
225 if (ep->valence==EpNEW)
226 switch(flag)
227 {
228 case chk_ERROR:
229 /* Do nothing until we can report a meaningful error message
230 The extra variable will be cleaned-up anyway */
231 case chk_CREATE:
232 pari_var_create(ep);
233 ep->valence = EpVAR;
234 ep->value = initial_value(ep);
235 break;
236 case chk_NOCREATE:
237 break;
238 }
239 else if (ep->valence!=EpVAR)
240 pari_err(e_MISC, "attempt to change built-in %s", ep->name);
241 }
242
243 INLINE GEN
checkvalueptr(entree * ep)244 checkvalueptr(entree *ep)
245 {
246 checkvalue(ep, chk_NOCREATE);
247 return ep->valence==EpNEW? gen_0: (GEN)ep->value;
248 }
249
250 /* make GP variables safe for set_avma(top) */
251 static void
lvar_make_safe(void)252 lvar_make_safe(void)
253 {
254 long n;
255 entree *ep;
256 for (n = 0; n < functions_tblsz; n++)
257 for (ep = functions_hash[n]; ep; ep = ep->next)
258 if (EpVALENCE(ep) == EpVAR)
259 { /* make sure ep->value is a COPY */
260 var_cell *v = (var_cell*)ep->pvalue;
261 if (v && v->flag == PUSH_VAL) {
262 GEN x = (GEN)ep->value;
263 if (x) changevalue(ep, (GEN)ep->value); else pop_val(ep);
264 }
265 }
266 }
267
268 static void
check_array_index(long c,long l)269 check_array_index(long c, long l)
270 {
271 if (c < 1) pari_err_COMPONENT("", "<", gen_1, stoi(c));
272 if (c >= l) pari_err_COMPONENT("", ">", stoi(l-1), stoi(c));
273 }
274
275 GEN*
safegel(GEN x,long l)276 safegel(GEN x, long l)
277 {
278 if (!is_matvec_t(typ(x)))
279 pari_err_TYPE("safegel",x);
280 check_array_index(l, lg(x));
281 return &(gel(x,l));
282 }
283
284 GEN*
safelistel(GEN x,long l)285 safelistel(GEN x, long l)
286 {
287 GEN d;
288 if (typ(x)!=t_LIST || list_typ(x)!=t_LIST_RAW)
289 pari_err_TYPE("safelistel",x);
290 d = list_data(x);
291 check_array_index(l, lg(d));
292 return &(gel(d,l));
293 }
294
295 long*
safeel(GEN x,long l)296 safeel(GEN x, long l)
297 {
298 if (typ(x)!=t_VECSMALL)
299 pari_err_TYPE("safeel",x);
300 check_array_index(l, lg(x));
301 return &(x[l]);
302 }
303
304 GEN*
safegcoeff(GEN x,long a,long b)305 safegcoeff(GEN x, long a, long b)
306 {
307 if (typ(x)!=t_MAT) pari_err_TYPE("safegcoeff", x);
308 check_array_index(b, lg(x));
309 check_array_index(a, lg(gel(x,b)));
310 return &(gcoeff(x,a,b));
311 }
312
313 typedef struct matcomp
314 {
315 GEN *ptcell;
316 GEN parent;
317 int full_col, full_row;
318 } matcomp;
319
320 typedef struct gp_pointer
321 {
322 matcomp c;
323 GEN x, ox;
324 entree *ep;
325 long vn;
326 long sp;
327 } gp_pointer;
328
329 /* assign res at *pt in "simple array object" p and return it, or a copy.*/
330 static void
change_compo(matcomp * c,GEN res)331 change_compo(matcomp *c, GEN res)
332 {
333 GEN p = c->parent, *pt = c->ptcell;
334 long i, t;
335
336 if (typ(p) == t_VECSMALL)
337 {
338 if (typ(res) != t_INT || is_bigint(res))
339 pari_err_TYPE("t_VECSMALL assignment", res);
340 *pt = (GEN)itos(res); return;
341 }
342 t = typ(res);
343 if (c->full_row)
344 {
345 if (t != t_VEC) pari_err_TYPE("matrix row assignment", res);
346 if (lg(res) != lg(p)) pari_err_DIM("matrix row assignment");
347 for (i=1; i<lg(p); i++)
348 {
349 GEN p1 = gcoeff(p,c->full_row,i); /* Protect against SIGINT */
350 gcoeff(p,c->full_row,i) = gclone(gel(res,i));
351 if (isclone(p1)) gunclone_deep(p1);
352 }
353 return;
354 }
355 if (c->full_col)
356 {
357 if (t != t_COL) pari_err_TYPE("matrix col assignment", res);
358 if (lg(res) != lg(*pt)) pari_err_DIM("matrix col assignment");
359 }
360
361 res = gclone(res);
362 gunclone_deep(*pt);
363 *pt = res;
364 }
365
366 /***************************************************************************
367 ** **
368 ** Byte-code evaluator **
369 ** **
370 ***************************************************************************/
371
372 struct var_lex
373 {
374 long flag;
375 GEN value;
376 };
377
378 struct trace
379 {
380 long pc;
381 GEN closure;
382 };
383
384 static THREAD long sp, rp, dbg_level;
385 static THREAD long *st, *precs;
386 static THREAD GEN *locks;
387 static THREAD gp_pointer *ptrs;
388 static THREAD entree **lvars;
389 static THREAD struct var_lex *var;
390 static THREAD struct trace *trace;
391 static THREAD pari_stack s_st, s_ptrs, s_var, s_trace, s_prec;
392 static THREAD pari_stack s_lvars, s_locks;
393
394 static void
changelex(long vn,GEN x)395 changelex(long vn, GEN x)
396 {
397 struct var_lex *v=var+s_var.n+vn;
398 GEN old_val = v->value;
399 v->value = gclone(x);
400 if (v->flag == COPY_VAL) gunclone_deep(old_val); else v->flag = COPY_VAL;
401 }
402
403 INLINE GEN
copylex(long vn)404 copylex(long vn)
405 {
406 struct var_lex *v = var+s_var.n+vn;
407 if (v->flag!=COPY_VAL && v->flag!=REF_VAL)
408 {
409 v->value = gclone(v->value);
410 v->flag = COPY_VAL;
411 }
412 return v->value;
413 }
414
415 INLINE void
setreflex(long vn)416 setreflex(long vn)
417 {
418 struct var_lex *v = var+s_var.n+vn;
419 v->flag = REF_VAL;
420 }
421
422 INLINE void
pushlex(long vn,GEN x)423 pushlex(long vn, GEN x)
424 {
425 struct var_lex *v=var+s_var.n+vn;
426 v->flag = PUSH_VAL;
427 v->value = x;
428 }
429
430 INLINE void
freelex(void)431 freelex(void)
432 {
433 struct var_lex *v=var+s_var.n-1;
434 s_var.n--;
435 if (v->flag == COPY_VAL) gunclone_deep(v->value);
436 }
437
438 INLINE void
restore_vars(long nbmvar,long nblvar,long nblock)439 restore_vars(long nbmvar, long nblvar, long nblock)
440 {
441 long j;
442 for(j=1;j<=nbmvar;j++)
443 freelex();
444 for(j=1;j<=nblvar;j++)
445 { s_lvars.n--; pop_val(lvars[s_lvars.n]); }
446 for(j=1;j<=nblock;j++)
447 { s_locks.n--; gunclone(locks[s_locks.n]); }
448 }
449
450 INLINE void
restore_trace(long nbtrace)451 restore_trace(long nbtrace)
452 {
453 long j;
454 for(j=1;j<=nbtrace;j++)
455 {
456 GEN C = trace[s_trace.n-j].closure;
457 clone_unlock(C);
458 }
459 s_trace.n-=nbtrace;
460 }
461
462 INLINE long
trace_push(long pc,GEN C)463 trace_push(long pc, GEN C)
464 {
465 long tr;
466 BLOCK_SIGINT_START
467 tr = pari_stack_new(&s_trace);
468 trace[tr].pc = pc;
469 clone_lock(C);
470 trace[tr].closure = C;
471 BLOCK_SIGINT_END
472 return tr;
473 }
474
475 void
push_lex(GEN a,GEN C)476 push_lex(GEN a, GEN C)
477 {
478 long vn=pari_stack_new(&s_var);
479 struct var_lex *v=var+vn;
480 v->flag = PUSH_VAL;
481 v->value = a;
482 if (C) (void) trace_push(-1, C);
483 }
484
485 GEN
get_lex(long vn)486 get_lex(long vn)
487 {
488 struct var_lex *v=var+s_var.n+vn;
489 return v->value;
490 }
491
492 void
set_lex(long vn,GEN x)493 set_lex(long vn, GEN x)
494 {
495 struct var_lex *v=var+s_var.n+vn;
496 if (v->flag == COPY_VAL) { gunclone_deep(v->value); v->flag = PUSH_VAL; }
497 v->value = x;
498 }
499
500 void
pop_lex(long n)501 pop_lex(long n)
502 {
503 long j;
504 for(j=1; j<=n; j++)
505 freelex();
506 s_trace.n--;
507 }
508
509 static THREAD pari_stack s_relocs;
510 static THREAD entree **relocs;
511
512 void
pari_init_evaluator(void)513 pari_init_evaluator(void)
514 {
515 sp=0;
516 pari_stack_init(&s_st,sizeof(*st),(void**)&st);
517 pari_stack_alloc(&s_st,32);
518 s_st.n=s_st.alloc;
519 rp=0;
520 pari_stack_init(&s_ptrs,sizeof(*ptrs),(void**)&ptrs);
521 pari_stack_alloc(&s_ptrs,16);
522 s_ptrs.n=s_ptrs.alloc;
523 pari_stack_init(&s_var,sizeof(*var),(void**)&var);
524 pari_stack_init(&s_lvars,sizeof(*lvars),(void**)&lvars);
525 pari_stack_init(&s_locks,sizeof(*locks),(void**)&locks);
526 pari_stack_init(&s_trace,sizeof(*trace),(void**)&trace);
527 br_res = NULL;
528 pari_stack_init(&s_relocs,sizeof(*relocs),(void**)&relocs);
529 pari_stack_init(&s_prec,sizeof(*precs),(void**)&precs);
530 }
531 void
pari_close_evaluator(void)532 pari_close_evaluator(void)
533 {
534 pari_stack_delete(&s_st);
535 pari_stack_delete(&s_ptrs);
536 pari_stack_delete(&s_var);
537 pari_stack_delete(&s_lvars);
538 pari_stack_delete(&s_trace);
539 pari_stack_delete(&s_relocs);
540 pari_stack_delete(&s_prec);
541 }
542
543 static gp_pointer *
new_ptr(void)544 new_ptr(void)
545 {
546 if (rp==s_ptrs.n-1)
547 {
548 long i;
549 gp_pointer *old = ptrs;
550 (void)pari_stack_new(&s_ptrs);
551 if (old != ptrs)
552 for(i=0; i<rp; i++)
553 {
554 gp_pointer *g = &ptrs[i];
555 if(g->sp >= 0) gel(st,g->sp) = (GEN) &(g->x);
556 }
557 }
558 return &ptrs[rp++];
559 }
560
561 void
push_localbitprec(long p)562 push_localbitprec(long p)
563 {
564 long n = pari_stack_new(&s_prec);
565 precs[n] = p;
566 }
567 void
push_localprec(long p)568 push_localprec(long p) { push_localbitprec(prec2nbits(p)); }
569
570 void
pop_localprec(void)571 pop_localprec(void) { s_prec.n--; }
572
573 long
get_localbitprec(void)574 get_localbitprec(void) { return s_prec.n? precs[s_prec.n-1]: precreal; }
575
576 long
get_localprec(void)577 get_localprec(void) { return nbits2prec(get_localbitprec()); }
578
579 static void
checkprec(const char * f,long p,long M)580 checkprec(const char *f, long p, long M)
581 {
582 if (p < 1) pari_err_DOMAIN(f, "p", "<", gen_1, stoi(p));
583 if (p > M) pari_err_DOMAIN(f, "p", ">", utoipos(M), utoi(p));
584 }
585 static long
_prec(GEN p,const char * f)586 _prec(GEN p, const char *f)
587 {
588 pari_sp av = avma;
589 if (typ(p) == t_INT) return itos(p);
590 p = gceil(p);
591 if (typ(p) != t_INT) pari_err_TYPE(f, p);
592 return gc_long(av, itos(p));
593 }
594 void
localprec(GEN pp)595 localprec(GEN pp)
596 {
597 long p = _prec(pp, "localprec");
598 checkprec("localprec", p, prec2ndec(LGBITS));
599 p = ndec2nbits(p); push_localbitprec(p);
600 }
601 void
localbitprec(GEN pp)602 localbitprec(GEN pp)
603 {
604 long p = _prec(pp, "localbitprec");
605 checkprec("localbitprec", p, (long)LGBITS);
606 push_localbitprec(p);
607 }
608 long
getlocalprec(long prec)609 getlocalprec(long prec) { return prec2ndec(prec); }
610 long
getlocalbitprec(long bit)611 getlocalbitprec(long bit) { return bit; }
612
613 static GEN
_precision0(GEN x)614 _precision0(GEN x)
615 {
616 long a = gprecision(x);
617 return a? utoi(prec2ndec(a)): mkoo();
618 }
619 GEN
precision0(GEN x,long n)620 precision0(GEN x, long n)
621 { return n? gprec(x,n): _precision0(x); }
622 static GEN
_bitprecision0(GEN x)623 _bitprecision0(GEN x)
624 {
625 long a = gprecision(x);
626 return a? utoi(prec2nbits(a)): mkoo();
627 }
628 GEN
bitprecision0(GEN x,long n)629 bitprecision0(GEN x, long n)
630 {
631 if (n < 0)
632 pari_err_DOMAIN("bitprecision", "bitprecision", "<", gen_0, stoi(n));
633 if (n) {
634 pari_sp av = avma;
635 GEN y = gprec_w(x, nbits2prec(n));
636 return gerepilecopy(av, y);
637 }
638 return _bitprecision0(x);
639 }
640 GEN
precision00(GEN x,GEN n)641 precision00(GEN x, GEN n)
642 {
643 if (!n) return _precision0(x);
644 return precision0(x, _prec(n, "precision"));
645 }
646 GEN
bitprecision00(GEN x,GEN n)647 bitprecision00(GEN x, GEN n)
648 {
649 if (!n) return _bitprecision0(x);
650 return bitprecision0(x, _prec(n, "bitprecision"));
651 }
652
653 INLINE GEN
copyupto(GEN z,GEN t)654 copyupto(GEN z, GEN t)
655 {
656 if (is_universal_constant(z) || (z>(GEN)pari_mainstack->bot && z<=t))
657 return z;
658 else
659 return gcopy(z);
660 }
661
662 static void closure_eval(GEN C);
663
664 INLINE GEN
get_and_reset_break(void)665 get_and_reset_break(void)
666 {
667 GEN z = br_res? gcopy(br_res): gnil;
668 reset_break(); return z;
669 }
670
671 INLINE GEN
closure_return(GEN C)672 closure_return(GEN C)
673 {
674 pari_sp av = avma;
675 closure_eval(C);
676 if (br_status) { set_avma(av); return get_and_reset_break(); }
677 return gerepileupto(av, gel(st,--sp));
678 }
679
680 /* for the break_loop debugger. Not memory clean */
681 GEN
closure_evalbrk(GEN C,long * status)682 closure_evalbrk(GEN C, long *status)
683 {
684 closure_eval(C); *status = br_status;
685 return br_status? get_and_reset_break(): gel(st,--sp);
686 }
687
688 INLINE long
closure_varn(GEN x)689 closure_varn(GEN x)
690 {
691 if (!x) return -1;
692 if (!gequalX(x)) err_var(x);
693 return varn(x);
694 }
695
696 INLINE void
closure_castgen(GEN z,long mode)697 closure_castgen(GEN z, long mode)
698 {
699 switch (mode)
700 {
701 case Ggen:
702 gel(st,sp++)=z;
703 break;
704 case Gsmall:
705 st[sp++]=gtos(z);
706 break;
707 case Gusmall:
708 st[sp++]=gtou(z);
709 break;
710 case Gvar:
711 st[sp++]=closure_varn(z);
712 break;
713 case Gvoid:
714 break;
715 default:
716 pari_err_BUG("closure_castgen, type unknown");
717 }
718 }
719
720 INLINE void
closure_castlong(long z,long mode)721 closure_castlong(long z, long mode)
722 {
723 switch (mode)
724 {
725 case Gsmall:
726 st[sp++]=z;
727 break;
728 case Gusmall:
729 if (z < 0)
730 pari_err_TYPE("stou [integer >=0 expected]", stoi(z));
731 st[sp++]=(ulong) z;
732 break;
733 case Ggen:
734 gel(st,sp++)=stoi(z);
735 break;
736 case Gvar:
737 err_var(stoi(z));
738 case Gvoid:
739 break;
740 default:
741 pari_err_BUG("closure_castlong, type unknown");
742 }
743 }
744
745 const char *
closure_func_err(void)746 closure_func_err(void)
747 {
748 long fun=s_trace.n-1, pc;
749 const char *code;
750 GEN C, oper;
751 if (fun < 0 || trace[fun].pc < 0) return NULL;
752 pc = trace[fun].pc; C = trace[fun].closure;
753 code = closure_codestr(C); oper = closure_get_oper(C);
754 if (code[pc]==OCcallgen || code[pc]==OCcallgen2 ||
755 code[pc]==OCcallint || code[pc]==OCcalllong || code[pc]==OCcallvoid)
756 return ((entree*)oper[pc])->name;
757 return NULL;
758 }
759
760 /* return the next label for the call chain debugger closure_err(),
761 * incorporating the name of the user of member function. Return NULL for an
762 * anonymous (inline) closure. */
763 static char *
get_next_label(const char * s,int member,char ** next_fun)764 get_next_label(const char *s, int member, char **next_fun)
765 {
766 const char *v, *t = s+1;
767 char *u, *next_label;
768
769 if (!is_keyword_char(*s)) return NULL;
770 while (is_keyword_char(*t)) t++;
771 /* e.g. (x->1/x)(0) instead of (x)->1/x */
772 if (t[0] == '-' && t[1] == '>') return NULL;
773 next_label = (char*)pari_malloc(t - s + 32);
774 sprintf(next_label, "in %sfunction ", member? "member ": "");
775 u = *next_fun = next_label + strlen(next_label);
776 v = s;
777 while (v < t) *u++ = *v++;
778 *u++ = 0; return next_label;
779 }
780
781 static const char *
get_arg_name(GEN C,long i)782 get_arg_name(GEN C, long i)
783 {
784 GEN d = closure_get_dbg(C), frpc = gel(d,2), fram = gel(d,3);
785 long j, l = lg(frpc);
786 for (j=1; j<l; j++)
787 if (frpc[j]==1 && i<lg(gel(fram,j)))
788 return ((entree*)mael(fram,j,i))->name;
789 return "(unnamed)";
790 }
791
792 void
closure_err(long level)793 closure_err(long level)
794 {
795 GEN base;
796 const long lastfun = s_trace.n - 1 - level;
797 char *next_label, *next_fun;
798 long i = maxss(0, lastfun - 19);
799 if (lastfun < 0) return; /*e.g. when called by gp_main_loop's simplify */
800 if (i > 0) while (lg(trace[i].closure)==6) i--;
801 base = closure_get_text(trace[i].closure); /* gcc -Wall*/
802 next_label = pari_strdup(i == 0? "at top-level": "[...] at");
803 next_fun = next_label;
804 for (; i <= lastfun; i++)
805 {
806 GEN C = trace[i].closure;
807 if (lg(C) >= 7) base=closure_get_text(C);
808 if ((i==lastfun || lg(trace[i+1].closure)>=7))
809 {
810 GEN dbg = gel(closure_get_dbg(C),1);
811 /* After a SIGINT, pc can be slightly off: ensure 0 <= pc < lg() */
812 long pc = minss(lg(dbg)-1, trace[i].pc>=0 ? trace[i].pc: 1);
813 long offset = pc? dbg[pc]: 0;
814 int member;
815 const char *s, *sbase;
816 if (typ(base)!=t_VEC) sbase = GSTR(base);
817 else if (offset>=0) sbase = GSTR(gel(base,2));
818 else { sbase = GSTR(gel(base,1)); offset += strlen(sbase); }
819 s = sbase + offset;
820 member = offset>0 && (s[-1] == '.');
821 /* avoid "in function foo: foo" */
822 if (!next_fun || strcmp(next_fun, s)) {
823 print_errcontext(pariErr, next_label, s, sbase);
824 out_putc(pariErr, '\n');
825 }
826 pari_free(next_label);
827 if (i == lastfun) break;
828
829 next_label = get_next_label(s, member, &next_fun);
830 if (!next_label) {
831 next_label = pari_strdup("in anonymous function");
832 next_fun = NULL;
833 }
834 }
835 }
836 }
837
838 GEN
pari_self(void)839 pari_self(void)
840 {
841 long fun = s_trace.n - 1;
842 if (fun > 0) while (lg(trace[fun].closure)==6) fun--;
843 return fun >= 0 ? trace[fun].closure: NULL;
844 }
845
846 long
closure_context(long start,long level)847 closure_context(long start, long level)
848 {
849 const long lastfun = s_trace.n - 1 - level;
850 long i, fun = lastfun;
851 if (fun<0) return lastfun;
852 while (fun>start && lg(trace[fun].closure)==6) fun--;
853 for (i=fun; i <= lastfun; i++)
854 push_frame(trace[i].closure, trace[i].pc,0);
855 for ( ; i < s_trace.n; i++)
856 push_frame(trace[i].closure, trace[i].pc,1);
857 return s_trace.n-level;
858 }
859
860 INLINE void
st_alloc(long n)861 st_alloc(long n)
862 {
863 if (sp+n>s_st.n)
864 {
865 pari_stack_alloc(&s_st,n+16);
866 s_st.n=s_st.alloc;
867 if (DEBUGMEM>=2) pari_warn(warner,"doubling evaluator stack");
868 }
869 }
870
871 INLINE void
ptr_proplock(gp_pointer * g,GEN C)872 ptr_proplock(gp_pointer *g, GEN C)
873 {
874 g->x = C;
875 if (isclone(g->x))
876 {
877 clone_unlock_deep(g->ox);
878 g->ox = g->x;
879 ++bl_refc(g->ox);
880 }
881 }
882
883 static void
closure_eval(GEN C)884 closure_eval(GEN C)
885 {
886 const char *code=closure_codestr(C);
887 GEN oper=closure_get_oper(C);
888 GEN data=closure_get_data(C);
889 long loper=lg(oper);
890 long saved_sp=sp-closure_arity(C);
891 long saved_rp=rp, saved_prec=s_prec.n;
892 long j, nbmvar=0, nblvar=0, nblock=0;
893 long pc, t;
894 #ifdef STACK_CHECK
895 GEN stackelt;
896 if (PARI_stack_limit && (void*) &stackelt <= PARI_stack_limit)
897 pari_err(e_MISC, "deep recursion");
898 #endif
899 t = trace_push(0, C);
900 if (lg(C)==8)
901 {
902 GEN z=closure_get_frame(C);
903 long l=lg(z)-1;
904 pari_stack_alloc(&s_var,l);
905 s_var.n+=l;
906 nbmvar+=l;
907 for(j=1;j<=l;j++)
908 {
909 var[s_var.n-j].flag=PUSH_VAL;
910 var[s_var.n-j].value=gel(z,j);
911 }
912 }
913
914 for(pc=1;pc<loper;pc++)
915 {
916 op_code opcode=(op_code) code[pc];
917 long operand=oper[pc];
918 if (sp<0) pari_err_BUG("closure_eval, stack underflow");
919 st_alloc(16);
920 trace[t].pc = pc;
921 CHECK_CTRLC
922 switch(opcode)
923 {
924 case OCpushlong:
925 st[sp++]=operand;
926 break;
927 case OCpushgnil:
928 gel(st,sp++)=gnil;
929 break;
930 case OCpushgen:
931 gel(st,sp++)=gel(data,operand);
932 break;
933 case OCpushreal:
934 gel(st,sp++)=strtor(GSTR(data[operand]),get_localprec());
935 break;
936 case OCpushstoi:
937 gel(st,sp++)=stoi(operand);
938 break;
939 case OCpushvar:
940 {
941 entree *ep = (entree *)operand;
942 gel(st,sp++)=pol_x(pari_var_create(ep));
943 break;
944 }
945 case OCpushdyn:
946 {
947 entree *ep = (entree *)operand;
948 if (!mt_is_thread())
949 {
950 checkvalue(ep, chk_CREATE);
951 gel(st,sp++)=(GEN)ep->value;
952 } else
953 {
954 GEN val = export_get(ep->name);
955 if (!val)
956 pari_err(e_MISC,"mt: please use export(%s)", ep->name);
957 gel(st,sp++)=val;
958 }
959 break;
960 }
961 case OCpushlex:
962 gel(st,sp++)=var[s_var.n+operand].value;
963 break;
964 case OCsimpleptrdyn:
965 {
966 gp_pointer *g = new_ptr();
967 g->vn=0;
968 g->ep = (entree*) operand;
969 g->x = checkvalueptr(g->ep);
970 g->ox = g->x; clone_lock(g->ox);
971 g->sp = sp;
972 gel(st,sp++) = (GEN)&(g->x);
973 break;
974 }
975 case OCsimpleptrlex:
976 {
977 gp_pointer *g = new_ptr();
978 g->vn=operand;
979 g->ep=(entree *)0x1L;
980 g->x = (GEN) var[s_var.n+operand].value;
981 g->ox = g->x; clone_lock(g->ox);
982 g->sp = sp;
983 gel(st,sp++) = (GEN)&(g->x);
984 break;
985 }
986 case OCnewptrdyn:
987 {
988 entree *ep = (entree *)operand;
989 gp_pointer *g = new_ptr();
990 matcomp *C;
991 checkvalue(ep, chk_ERROR);
992 g->sp = -1;
993 g->x = copyvalue(ep);
994 g->ox = g->x; clone_lock(g->ox);
995 g->vn=0;
996 g->ep=NULL;
997 C=&g->c;
998 C->full_col = C->full_row = 0;
999 C->parent = (GEN) g->x;
1000 C->ptcell = (GEN *) &g->x;
1001 break;
1002 }
1003 case OCnewptrlex:
1004 {
1005 gp_pointer *g = new_ptr();
1006 matcomp *C;
1007 g->sp = -1;
1008 g->x = copylex(operand);
1009 g->ox = g->x; clone_lock(g->ox);
1010 g->vn=0;
1011 g->ep=NULL;
1012 C=&g->c;
1013 C->full_col = C->full_row = 0;
1014 C->parent = (GEN) g->x;
1015 C->ptcell = (GEN *) &(g->x);
1016 break;
1017 }
1018 case OCpushptr:
1019 {
1020 gp_pointer *g = &ptrs[rp-1];
1021 g->sp = sp;
1022 gel(st,sp++) = (GEN)&(g->x);
1023 }
1024 break;
1025 case OCendptr:
1026 for(j=0;j<operand;j++)
1027 {
1028 gp_pointer *g = &ptrs[--rp];
1029 if (g->ep)
1030 {
1031 if (g->vn)
1032 changelex(g->vn, g->x);
1033 else
1034 changevalue(g->ep, g->x);
1035 }
1036 else change_compo(&(g->c), g->x);
1037 clone_unlock_deep(g->ox);
1038 }
1039 break;
1040 case OCstoredyn:
1041 {
1042 entree *ep = (entree *)operand;
1043 checkvalue(ep, chk_NOCREATE);
1044 changevalue(ep, gel(st,--sp));
1045 break;
1046 }
1047 case OCstorelex:
1048 changelex(operand,gel(st,--sp));
1049 break;
1050 case OCstoreptr:
1051 {
1052 gp_pointer *g = &ptrs[--rp];
1053 change_compo(&(g->c), gel(st,--sp));
1054 clone_unlock_deep(g->ox);
1055 break;
1056 }
1057 case OCstackgen:
1058 {
1059 GEN z = gerepileupto(st[sp-2],gel(st,sp-1));
1060 gmael(st,sp-3,operand) = copyupto(z,gel(st,sp-2));
1061 st[sp-2] = avma;
1062 sp--;
1063 break;
1064 }
1065 case OCprecreal:
1066 st[sp++]=get_localprec();
1067 break;
1068 case OCbitprecreal:
1069 st[sp++]=get_localbitprec();
1070 break;
1071 case OCprecdl:
1072 st[sp++]=precdl;
1073 break;
1074 case OCavma:
1075 st[sp++]=avma;
1076 break;
1077 case OCcowvardyn:
1078 {
1079 entree *ep = (entree *)operand;
1080 checkvalue(ep, chk_ERROR);
1081 (void)copyvalue(ep);
1082 break;
1083 }
1084 case OCcowvarlex:
1085 (void)copylex(operand);
1086 break;
1087 case OCsetref:
1088 setreflex(operand);
1089 break;
1090 case OClock:
1091 {
1092 GEN v = gel(st,sp-1);
1093 if (isclone(v))
1094 {
1095 long n = pari_stack_new(&s_locks);
1096 locks[n] = v;
1097 nblock++;
1098 ++bl_refc(v);
1099 }
1100 break;
1101 }
1102 case OCstoi:
1103 gel(st,sp-1)=stoi(st[sp-1]);
1104 break;
1105 case OCutoi:
1106 gel(st,sp-1)=utoi(st[sp-1]);
1107 break;
1108 case OCitos:
1109 st[sp+operand]=gtos(gel(st,sp+operand));
1110 break;
1111 case OCitou:
1112 st[sp+operand]=gtou(gel(st,sp+operand));
1113 break;
1114 case OCtostr:
1115 {
1116 GEN z = gel(st,sp+operand);
1117 st[sp+operand] = (long) (z ? GENtostr_unquoted(z): NULL);
1118 break;
1119 }
1120 case OCvarn:
1121 st[sp+operand] = closure_varn(gel(st,sp+operand));
1122 break;
1123 case OCcopy:
1124 gel(st,sp-1) = gcopy(gel(st,sp-1));
1125 break;
1126 case OCgerepile:
1127 {
1128 pari_sp av;
1129 GEN x;
1130 sp--;
1131 av = st[sp-1];
1132 x = gel(st,sp);
1133 if (isonstack(x))
1134 {
1135 pari_sp av2 = (pari_sp)(x + lg(x));
1136 if ((long) (av - av2) > 1000000L)
1137 {
1138 if (DEBUGMEM>=2)
1139 pari_warn(warnmem,"eval: recovering %ld bytes", av - av2);
1140 x = gerepileupto(av, x);
1141 }
1142 } else set_avma(av);
1143 gel(st,sp-1) = x;
1144 break;
1145 }
1146 case OCcopyifclone:
1147 if (isclone(gel(st,sp-1)))
1148 gel(st,sp-1) = gcopy(gel(st,sp-1));
1149 break;
1150 case OCcompo1:
1151 {
1152 GEN p=gel(st,sp-2);
1153 long c=st[sp-1];
1154 sp-=2;
1155 switch(typ(p))
1156 {
1157 case t_VEC: case t_COL:
1158 check_array_index(c, lg(p));
1159 closure_castgen(gel(p,c),operand);
1160 break;
1161 case t_LIST:
1162 {
1163 long lx;
1164 if (list_typ(p)!=t_LIST_RAW)
1165 pari_err_TYPE("_[_] OCcompo1 [not a vector]", p);
1166 p = list_data(p); lx = p? lg(p): 1;
1167 check_array_index(c, lx);
1168 closure_castgen(gel(p,c),operand);
1169 break;
1170 }
1171 case t_VECSMALL:
1172 check_array_index(c,lg(p));
1173 closure_castlong(p[c],operand);
1174 break;
1175 default:
1176 pari_err_TYPE("_[_] OCcompo1 [not a vector]", p);
1177 break;
1178 }
1179 break;
1180 }
1181 case OCcompo1ptr:
1182 {
1183 long c=st[sp-1];
1184 long lx;
1185 gp_pointer *g = &ptrs[rp-1];
1186 matcomp *C=&g->c;
1187 GEN p = g->x;
1188 sp--;
1189 switch(typ(p))
1190 {
1191 case t_VEC: case t_COL:
1192 check_array_index(c, lg(p));
1193 C->ptcell = (GEN *) p+c;
1194 ptr_proplock(g, *(C->ptcell));
1195 break;
1196 case t_VECSMALL:
1197 check_array_index(c, lg(p));
1198 C->ptcell = (GEN *) p+c;
1199 g->x = stoi(p[c]);
1200 break;
1201 case t_LIST:
1202 if (list_typ(p)!=t_LIST_RAW)
1203 pari_err_TYPE("&_[_] OCcompo1 [not a vector]", p);
1204 p = list_data(p); lx = p? lg(p): 1;
1205 check_array_index(c,lx);
1206 C->ptcell = (GEN *) p+c;
1207 ptr_proplock(g, *(C->ptcell));
1208 break;
1209 default:
1210 pari_err_TYPE("&_[_] OCcompo1ptr [not a vector]", p);
1211 }
1212 C->parent = p;
1213 break;
1214 }
1215 case OCcompo2:
1216 {
1217 GEN p=gel(st,sp-3);
1218 long c=st[sp-2];
1219 long d=st[sp-1];
1220 if (typ(p)!=t_MAT) pari_err_TYPE("_[_,_] OCcompo2 [not a matrix]", p);
1221 check_array_index(d, lg(p));
1222 check_array_index(c, lg(gel(p,d)));
1223 sp-=3;
1224 closure_castgen(gcoeff(p,c,d),operand);
1225 break;
1226 }
1227 case OCcompo2ptr:
1228 {
1229 long c=st[sp-2];
1230 long d=st[sp-1];
1231 gp_pointer *g = &ptrs[rp-1];
1232 matcomp *C=&g->c;
1233 GEN p = g->x;
1234 sp-=2;
1235 if (typ(p)!=t_MAT)
1236 pari_err_TYPE("&_[_,_] OCcompo2ptr [not a matrix]", p);
1237 check_array_index(d, lg(p));
1238 check_array_index(c, lg(gel(p,d)));
1239 C->ptcell = (GEN *) gel(p,d)+c;
1240 C->parent = p;
1241 ptr_proplock(g, *(C->ptcell));
1242 break;
1243 }
1244 case OCcompoC:
1245 {
1246 GEN p=gel(st,sp-2);
1247 long c=st[sp-1];
1248 if (typ(p)!=t_MAT)
1249 pari_err_TYPE("_[,_] OCcompoC [not a matrix]", p);
1250 check_array_index(c, lg(p));
1251 sp--;
1252 gel(st,sp-1) = gel(p,c);
1253 break;
1254 }
1255 case OCcompoCptr:
1256 {
1257 long c=st[sp-1];
1258 gp_pointer *g = &ptrs[rp-1];
1259 matcomp *C=&g->c;
1260 GEN p = g->x;
1261 sp--;
1262 if (typ(p)!=t_MAT)
1263 pari_err_TYPE("&_[,_] OCcompoCptr [not a matrix]", p);
1264 check_array_index(c, lg(p));
1265 C->ptcell = (GEN *) p+c;
1266 C->full_col = c;
1267 C->parent = p;
1268 ptr_proplock(g, *(C->ptcell));
1269 break;
1270 }
1271 case OCcompoL:
1272 {
1273 GEN p=gel(st,sp-2);
1274 long r=st[sp-1];
1275 sp--;
1276 if (typ(p)!=t_MAT)
1277 pari_err_TYPE("_[_,] OCcompoL [not a matrix]", p);
1278 check_array_index(r,lg(p) == 1? 1: lgcols(p));
1279 gel(st,sp-1) = row(p,r);
1280 break;
1281 }
1282 case OCcompoLptr:
1283 {
1284 long r=st[sp-1];
1285 gp_pointer *g = &ptrs[rp-1];
1286 matcomp *C=&g->c;
1287 GEN p = g->x, p2;
1288 sp--;
1289 if (typ(p)!=t_MAT)
1290 pari_err_TYPE("&_[_,] OCcompoLptr [not a matrix]", p);
1291 check_array_index(r,lg(p) == 1? 1: lgcols(p));
1292 p2 = rowcopy(p,r);
1293 C->full_row = r; /* record row number */
1294 C->ptcell = &p2;
1295 C->parent = p;
1296 g->x = p2;
1297 break;
1298 }
1299 case OCdefaultarg:
1300 if (var[s_var.n+operand].flag==DEFAULT_VAL)
1301 {
1302 GEN z = gel(st,sp-1);
1303 if (typ(z)==t_CLOSURE)
1304 {
1305 pushlex(operand, closure_evalnobrk(z));
1306 copylex(operand);
1307 }
1308 else
1309 pushlex(operand, z);
1310 }
1311 sp--;
1312 break;
1313 case OClocalvar:
1314 {
1315 long n;
1316 entree *ep = (entree *)operand;
1317 checkvalue(ep, chk_NOCREATE);
1318 n = pari_stack_new(&s_lvars);
1319 lvars[n] = ep;
1320 nblvar++;
1321 pushvalue(ep,gel(st,--sp));
1322 break;
1323 }
1324 case OClocalvar0:
1325 {
1326 long n;
1327 entree *ep = (entree *)operand;
1328 checkvalue(ep, chk_NOCREATE);
1329 n = pari_stack_new(&s_lvars);
1330 lvars[n] = ep;
1331 nblvar++;
1332 zerovalue(ep);
1333 break;
1334 }
1335 case OCexportvar:
1336 {
1337 entree *ep = (entree *)operand;
1338 mt_export_add(ep->name, gel(st,--sp));
1339 break;
1340 }
1341 case OCunexportvar:
1342 {
1343 entree *ep = (entree *)operand;
1344 mt_export_del(ep->name);
1345 break;
1346 }
1347
1348 #define EVAL_f(f) \
1349 switch (ep->arity) \
1350 { \
1351 case 0: f(); break; \
1352 case 1: sp--; f(st[sp]); break; \
1353 case 2: sp-=2; f(st[sp],st[sp+1]); break; \
1354 case 3: sp-=3; f(st[sp],st[sp+1],st[sp+2]); break; \
1355 case 4: sp-=4; f(st[sp],st[sp+1],st[sp+2],st[sp+3]); break; \
1356 case 5: sp-=5; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4]); break; \
1357 case 6: sp-=6; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5]); break; \
1358 case 7: sp-=7; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6]); break; \
1359 case 8: sp-=8; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7]); break; \
1360 case 9: sp-=9; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8]); break; \
1361 case 10: sp-=10; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9]); break; \
1362 case 11: sp-=11; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10]); break; \
1363 case 12: sp-=12; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11]); break; \
1364 case 13: sp-=13; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12]); break; \
1365 case 14: sp-=14; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13]); break; \
1366 case 15: sp-=15; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14]); break; \
1367 case 16: sp-=16; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15]); break; \
1368 case 17: sp-=17; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16]); break; \
1369 case 18: sp-=18; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16],st[sp+17]); break; \
1370 case 19: sp-=19; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16],st[sp+17],st[sp+18]); break; \
1371 case 20: sp-=20; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5],st[sp+6],st[sp+7],st[sp+8],st[sp+9],st[sp+10],st[sp+11],st[sp+12],st[sp+13],st[sp+14],st[sp+15],st[sp+16],st[sp+17],st[sp+18],st[sp+19]); break; \
1372 default: \
1373 pari_err_IMPL("functions with more than 20 parameters");\
1374 goto endeval; /*LCOV_EXCL_LINE*/ \
1375 }
1376
1377 case OCcallgen:
1378 {
1379 entree *ep = (entree *)operand;
1380 GEN res;
1381 /* Macro Madness : evaluate function ep->value on arguments
1382 * st[sp-ep->arity .. sp]. Set res = result. */
1383 EVAL_f(res = ((GEN (*)(ANYARG))ep->value));
1384 if (br_status) goto endeval;
1385 gel(st,sp++)=res;
1386 break;
1387 }
1388 case OCcallgen2: /*same for ep->arity = 2. Is this optimization worth it ?*/
1389 {
1390 entree *ep = (entree *)operand;
1391 GEN res;
1392 sp-=2;
1393 res = ((GEN (*)(GEN,GEN))ep->value)(gel(st,sp),gel(st,sp+1));
1394 if (br_status) goto endeval;
1395 gel(st,sp++)=res;
1396 break;
1397 }
1398 case OCcalllong:
1399 {
1400 entree *ep = (entree *)operand;
1401 long res;
1402 EVAL_f(res = ((long (*)(ANYARG))ep->value));
1403 if (br_status) goto endeval;
1404 st[sp++] = res;
1405 break;
1406 }
1407 case OCcallint:
1408 {
1409 entree *ep = (entree *)operand;
1410 long res;
1411 EVAL_f(res = ((int (*)(ANYARG))ep->value));
1412 if (br_status) goto endeval;
1413 st[sp++] = res;
1414 break;
1415 }
1416 case OCcallvoid:
1417 {
1418 entree *ep = (entree *)operand;
1419 EVAL_f(((void (*)(ANYARG))ep->value));
1420 if (br_status) goto endeval;
1421 break;
1422 }
1423 #undef EVAL_f
1424
1425 case OCcalluser:
1426 {
1427 long n=operand;
1428 GEN fun = gel(st,sp-1-n);
1429 long arity, isvar;
1430 GEN z;
1431 if (typ(fun)!=t_CLOSURE) pari_err(e_NOTFUNC, fun);
1432 isvar = closure_is_variadic(fun);
1433 arity = closure_arity(fun);
1434 if (!isvar || n < arity)
1435 {
1436 st_alloc(arity-n);
1437 if (n>arity)
1438 pari_err(e_MISC,"too many parameters in user-defined function call");
1439 for (j=n+1;j<=arity;j++)
1440 gel(st,sp++)=0;
1441 if (isvar) gel(st,sp-1) = cgetg(1,t_VEC);
1442 }
1443 else
1444 {
1445 GEN v;
1446 long j, m = n-arity+1;
1447 v = cgetg(m+1,t_VEC);
1448 sp-=m;
1449 for (j=1; j<=m; j++)
1450 gel(v,j) = gel(st,sp+j-1)? gcopy(gel(st,sp+j-1)): gen_0;
1451 gel(st,sp++)=v;
1452 }
1453 z = closure_return(fun);
1454 if (br_status) goto endeval;
1455 gel(st, sp-1) = z;
1456 break;
1457 }
1458 case OCnewframe:
1459 if (operand>0) nbmvar+=operand;
1460 else operand=-operand;
1461 pari_stack_alloc(&s_var,operand);
1462 s_var.n+=operand;
1463 for(j=1;j<=operand;j++)
1464 {
1465 var[s_var.n-j].flag=PUSH_VAL;
1466 var[s_var.n-j].value=gen_0;
1467 }
1468 break;
1469 case OCsaveframe:
1470 {
1471 GEN cl = (operand?gcopy:shallowcopy)(gel(st,sp-1));
1472 GEN f = gel(cl, 7);
1473 long j, l = lg(f);
1474 GEN v = cgetg(l, t_VEC);
1475 for (j = 1; j < l; j++)
1476 if (signe(gel(f,l-j))==0)
1477 {
1478 GEN val = var[s_var.n-j].value;
1479 gel(v,j) = operand?gcopy(val):val;
1480 } else
1481 gel(v,j) = gnil;
1482 gel(cl,7) = v;
1483 gel(st,sp-1) = cl;
1484 }
1485 break;
1486 case OCpackargs:
1487 {
1488 GEN def = cgetg(operand+1, t_VECSMALL);
1489 GEN args = cgetg(operand+1, t_VEC);
1490 pari_stack_alloc(&s_var,operand);
1491 sp-=operand;
1492 for (j=0;j<operand;j++)
1493 {
1494 if (gel(st,sp+j))
1495 {
1496 gel(args,j+1) = gel(st,sp+j);
1497 uel(def ,j+1) = 1;
1498 }
1499 else
1500 {
1501 gel(args,j+1) = gen_0;
1502 uel(def ,j+1) = 0;
1503 }
1504 }
1505 gel(st, sp++) = args;
1506 gel(st, sp++) = def;
1507 break;
1508 }
1509 case OCgetargs:
1510 pari_stack_alloc(&s_var,operand);
1511 s_var.n+=operand;
1512 nbmvar+=operand;
1513 sp-=operand;
1514 for (j=0;j<operand;j++)
1515 {
1516 if (gel(st,sp+j))
1517 pushlex(j-operand,gel(st,sp+j));
1518 else
1519 {
1520 var[s_var.n+j-operand].flag=DEFAULT_VAL;
1521 var[s_var.n+j-operand].value=gen_0;
1522 }
1523 }
1524 break;
1525 case OCcheckuserargs:
1526 for (j=0; j<operand; j++)
1527 if (var[s_var.n-operand+j].flag==DEFAULT_VAL)
1528 pari_err(e_MISC,"missing mandatory argument"
1529 " '%s' in user function",get_arg_name(C,j+1));
1530 break;
1531 case OCcheckargs:
1532 for (j=sp-1;operand;operand>>=1UL,j--)
1533 if ((operand&1L) && gel(st,j)==NULL)
1534 pari_err(e_MISC,"missing mandatory argument");
1535 break;
1536 case OCcheckargs0:
1537 for (j=sp-1;operand;operand>>=1UL,j--)
1538 if ((operand&1L) && gel(st,j))
1539 pari_err(e_MISC,"argument type not implemented");
1540 break;
1541 case OCdefaultlong:
1542 sp--;
1543 if (st[sp+operand])
1544 st[sp+operand]=gtos(gel(st,sp+operand));
1545 else
1546 st[sp+operand]=st[sp];
1547 break;
1548 case OCdefaultulong:
1549 sp--;
1550 if (st[sp+operand])
1551 st[sp+operand]=gtou(gel(st,sp+operand));
1552 else
1553 st[sp+operand]=st[sp];
1554 break;
1555 case OCdefaultgen:
1556 sp--;
1557 if (!st[sp+operand])
1558 st[sp+operand]=st[sp];
1559 break;
1560 case OCvec:
1561 gel(st,sp++)=cgetg(operand,t_VEC);
1562 st[sp++]=avma;
1563 break;
1564 case OCcol:
1565 gel(st,sp++)=cgetg(operand,t_COL);
1566 st[sp++]=avma;
1567 break;
1568 case OCmat:
1569 {
1570 GEN z;
1571 long l=st[sp-1];
1572 z=cgetg(operand,t_MAT);
1573 for(j=1;j<operand;j++)
1574 gel(z,j) = cgetg(l,t_COL);
1575 gel(st,sp-1) = z;
1576 st[sp++]=avma;
1577 }
1578 break;
1579 case OCpop:
1580 sp-=operand;
1581 break;
1582 case OCdup:
1583 {
1584 long i, s=st[sp-1];
1585 st_alloc(operand);
1586 for(i=1;i<=operand;i++)
1587 st[sp++]=s;
1588 }
1589 break;
1590 }
1591 }
1592 if (0)
1593 {
1594 endeval:
1595 sp = saved_sp;
1596 for( ; rp>saved_rp ; )
1597 {
1598 gp_pointer *g = &ptrs[--rp];
1599 clone_unlock_deep(g->ox);
1600 }
1601 }
1602 s_prec.n = saved_prec;
1603 s_trace.n--;
1604 restore_vars(nbmvar, nblvar, nblock);
1605 clone_unlock(C);
1606 }
1607
1608 GEN
closure_evalgen(GEN C)1609 closure_evalgen(GEN C)
1610 {
1611 pari_sp ltop=avma;
1612 closure_eval(C);
1613 if (br_status) return gc_NULL(ltop);
1614 return gerepileupto(ltop,gel(st,--sp));
1615 }
1616
1617 long
evalstate_get_trace(void)1618 evalstate_get_trace(void)
1619 { return s_trace.n; }
1620
1621 void
evalstate_set_trace(long lvl)1622 evalstate_set_trace(long lvl)
1623 { s_trace.n = lvl; }
1624
1625 void
evalstate_save(struct pari_evalstate * state)1626 evalstate_save(struct pari_evalstate *state)
1627 {
1628 state->avma = avma;
1629 state->sp = sp;
1630 state->rp = rp;
1631 state->prec = s_prec.n;
1632 state->var = s_var.n;
1633 state->lvars= s_lvars.n;
1634 state->locks= s_locks.n;
1635 state->trace= s_trace.n;
1636 compilestate_save(&state->comp);
1637 mtstate_save(&state->mt);
1638 }
1639
1640 void
evalstate_restore(struct pari_evalstate * state)1641 evalstate_restore(struct pari_evalstate *state)
1642 {
1643 set_avma(state->avma);
1644 mtstate_restore(&state->mt);
1645 sp = state->sp;
1646 rp = state->rp;
1647 s_prec.n = state->prec;
1648 restore_vars(s_var.n-state->var, s_lvars.n-state->lvars,
1649 s_locks.n-state->locks);
1650 restore_trace(s_trace.n-state->trace);
1651 reset_break();
1652 compilestate_restore(&state->comp);
1653 }
1654
1655 GEN
evalstate_restore_err(struct pari_evalstate * state)1656 evalstate_restore_err(struct pari_evalstate *state)
1657 {
1658 GENbin* err = copy_bin(pari_err_last());
1659 evalstate_restore(state);
1660 return bin_copy(err);
1661 }
1662
1663 void
evalstate_reset(void)1664 evalstate_reset(void)
1665 {
1666 mtstate_reset();
1667 sp = 0;
1668 rp = 0;
1669 dbg_level = 0;
1670 restore_vars(s_var.n, s_lvars.n, s_locks.n);
1671 s_trace.n = 0;
1672 reset_break();
1673 compilestate_reset();
1674 parsestate_reset();
1675 set_avma(pari_mainstack->top);
1676 }
1677
1678 void
evalstate_clone(void)1679 evalstate_clone(void)
1680 {
1681 long i;
1682 for (i = 1; i<=s_var.n; i++) copylex(-i);
1683 lvar_make_safe();
1684 for (i = 0; i< s_trace.n; i++)
1685 {
1686 GEN C = trace[i].closure;
1687 if (isonstack(C)) trace[i].closure = gclone(C);
1688 }
1689 }
1690
1691 GEN
closure_trapgen(GEN C,long numerr)1692 closure_trapgen(GEN C, long numerr)
1693 {
1694 VOLATILE GEN x;
1695 struct pari_evalstate state;
1696 evalstate_save(&state);
1697 pari_CATCH(numerr) { x = (GEN)1L; }
1698 pari_TRY { x = closure_evalgen(C); } pari_ENDCATCH;
1699 if (x == (GEN)1L) evalstate_restore(&state);
1700 return x;
1701 }
1702
1703 GEN
closure_evalnobrk(GEN C)1704 closure_evalnobrk(GEN C)
1705 {
1706 pari_sp ltop=avma;
1707 closure_eval(C);
1708 if (br_status) pari_err(e_MISC, "break not allowed here");
1709 return gerepileupto(ltop,gel(st,--sp));
1710 }
1711
1712 void
closure_evalvoid(GEN C)1713 closure_evalvoid(GEN C)
1714 {
1715 pari_sp ltop=avma;
1716 closure_eval(C);
1717 set_avma(ltop);
1718 }
1719
1720 GEN
closure_evalres(GEN C)1721 closure_evalres(GEN C)
1722 {
1723 return closure_return(C);
1724 }
1725
1726 INLINE GEN
closure_returnupto(GEN C)1727 closure_returnupto(GEN C)
1728 {
1729 pari_sp av=avma;
1730 return copyupto(closure_return(C),(GEN)av);
1731 }
1732
1733 GEN
pareval_worker(GEN C)1734 pareval_worker(GEN C)
1735 {
1736 return closure_callgenall(C, 0);
1737 }
1738
1739 GEN
pareval(GEN C)1740 pareval(GEN C)
1741 {
1742 pari_sp av = avma;
1743 long l = lg(C), i;
1744 GEN worker;
1745 if (!is_vec_t(typ(C))) pari_err_TYPE("pareval",C);
1746 for (i=1; i<l; i++)
1747 if (typ(gel(C,i))!=t_CLOSURE)
1748 pari_err_TYPE("pareval",gel(C,i));
1749 worker = snm_closure(is_entry("_pareval_worker"), NULL);
1750 return gerepileupto(av, gen_parapply(worker, C));
1751 }
1752
1753 GEN
parvector_worker(GEN i,GEN C)1754 parvector_worker(GEN i, GEN C)
1755 {
1756 return closure_callgen1(C, i);
1757 }
1758
1759 GEN
parfor_worker(GEN i,GEN C)1760 parfor_worker(GEN i, GEN C)
1761 {
1762 retmkvec2(gcopy(i), closure_callgen1(C, i));
1763 }
1764
1765 GEN
parvector(long n,GEN code)1766 parvector(long n, GEN code)
1767 {
1768 long i, pending = 0, workid;
1769 GEN worker = snm_closure(is_entry("_parvector_worker"), mkvec(code));
1770 GEN a, V, done;
1771 struct pari_mt pt;
1772 mt_queue_start_lim(&pt, worker, n);
1773 a = mkvec(cgetipos(3)); /* left on the stack */
1774 V = cgetg(n+1, t_VEC);
1775 for (i=1; i<=n || pending; i++)
1776 {
1777 mael(a,1,2) = i;
1778 mt_queue_submit(&pt, i, i<=n? a: NULL);
1779 done = mt_queue_get(&pt, &workid, &pending);
1780 if (done) gel(V,workid) = done;
1781 }
1782 mt_queue_end(&pt);
1783 return V;
1784 }
1785
1786 /* B <- {a + k * m : k = 0, ..., (b-a)/m)} */
1787 static void
arithprogset(GEN B,GEN a,GEN b,long m)1788 arithprogset(GEN B, GEN a, GEN b, long m)
1789 {
1790 long k;
1791 for (k = 1; cmpii(a, b) <= 0; a = addui(m,a), k++) gel(B, k) = a;
1792 setlg(B, k);
1793 }
1794 static GEN
vecsum_i(GEN v)1795 vecsum_i(GEN v)
1796 {
1797 long i, l = lg(v);
1798 GEN s;
1799 if (l == 1) return gen_0;
1800 s = gel(v,1); for (i = 2; i < l; i++) s = gadd(s, gel(v,i));
1801 return s;
1802 }
1803 GEN
parsum(GEN a,GEN b,GEN code)1804 parsum(GEN a, GEN b, GEN code)
1805 {
1806 pari_sp av = avma;
1807 GEN worker, L, v, s, N;
1808 long r, m, pending;
1809 struct pari_mt pt;
1810 pari_sp av2;
1811
1812 if (typ(a) != t_INT) pari_err_TYPE("parsum",a);
1813 if (gcmp(b,a) < 0) return gen_0;
1814 worker = snm_closure(is_entry("_parapply_slice_worker"), mkvec(code));
1815 b = gfloor(b);
1816 N = addiu(subii(b, a), 1);
1817 m = itou(sqrti(N)); if (cmpiu(N, m) < 0) m = itou(N);
1818 mt_queue_start_lim(&pt, worker, m);
1819 L = cgetg(m + 2, t_VEC); v = mkvec(L);
1820 s = gen_0; a = setloop(a); pending = 0; av2 = avma;
1821 for (r = 1; r <= m || pending; r++)
1822 {
1823 long workid;
1824 GEN done;
1825 if (r <= m) { arithprogset(L, icopy(a), b, m); a = incloop(a); }
1826 mt_queue_submit(&pt, 0, r <= m? v: NULL);
1827 done = mt_queue_get(&pt, &workid, &pending);
1828 if (done) s = gerepileupto(av2, gadd(s, vecsum_i(done)));
1829 }
1830 mt_queue_end(&pt); return gerepileupto(av, s);
1831 }
1832
1833 void
parfor(GEN a,GEN b,GEN code,void * E,long call (void *,GEN,GEN))1834 parfor(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN))
1835 {
1836 pari_sp av = avma, av2;
1837 long running, pending = 0, lim;
1838 long status = br_NONE;
1839 GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));
1840 GEN done, stop = NULL;
1841 struct pari_mt pt;
1842 if (typ(a) != t_INT) pari_err_TYPE("parfor",a);
1843 if (b)
1844 {
1845 if (gcmp(b,a) < 0) return;
1846 if (typ(b) == t_INFINITY)
1847 {
1848 if (inf_get_sign(b) < 0) return;
1849 b = NULL;
1850 }
1851 else
1852 b = gfloor(b);
1853 }
1854 lim = b ? itos_or_0(subii(addis(b,1),a)): 0;
1855 mt_queue_start_lim(&pt, worker, lim);
1856 a = mkvec(setloop(a));
1857 av2 = avma;
1858 while ((running = (!stop && (!b || cmpii(gel(a,1),b) <= 0))) || pending)
1859 {
1860 mt_queue_submit(&pt, 0, running ? a: NULL);
1861 done = mt_queue_get(&pt, NULL, &pending);
1862 if (call && done && (!stop || cmpii(gel(done,1),stop) < 0))
1863 if (call(E, gel(done,1), gel(done,2)))
1864 {
1865 status = br_status;
1866 br_status = br_NONE;
1867 stop = gerepileuptoint(av2, gel(done,1));
1868 }
1869 gel(a,1) = incloop(gel(a,1));
1870 if (!stop) set_avma(av2);
1871 }
1872 set_avma(av2);
1873 mt_queue_end(&pt);
1874 br_status = status;
1875 set_avma(av);
1876 }
1877
1878 static void
parforiter_init(struct parfor_iter * T,GEN code)1879 parforiter_init(struct parfor_iter *T, GEN code)
1880 {
1881 T->pending = 0;
1882 T->worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));
1883 mt_queue_start(&T->pt, T->worker);
1884 }
1885
1886 static GEN
parforiter_next(struct parfor_iter * T,GEN v)1887 parforiter_next(struct parfor_iter *T, GEN v)
1888 {
1889 mt_queue_submit(&T->pt, 0, v);
1890 return mt_queue_get(&T->pt, NULL, &T->pending);
1891 }
1892
1893 static void
parforiter_stop(struct parfor_iter * T)1894 parforiter_stop(struct parfor_iter *T)
1895 {
1896 while (T->pending)
1897 {
1898 mt_queue_submit(&T->pt, 0, NULL);
1899 (void) mt_queue_get(&T->pt, NULL, &T->pending);
1900 }
1901 mt_queue_end(&T->pt);
1902 }
1903
1904 void
parfor_init(parfor_t * T,GEN a,GEN b,GEN code)1905 parfor_init(parfor_t *T, GEN a, GEN b, GEN code)
1906 {
1907 if (typ(a) != t_INT) pari_err_TYPE("parfor",a);
1908 T->b = b ? gfloor(b): NULL;
1909 T->a = mkvec(setloop(a));
1910 parforiter_init(&T->iter, code);
1911 }
1912
1913 GEN
parfor_next(parfor_t * T)1914 parfor_next(parfor_t *T)
1915 {
1916 long running;
1917 while ((running=((!T->b || cmpii(gel(T->a,1),T->b) <= 0))) || T->iter.pending)
1918 {
1919 GEN done = parforiter_next(&T->iter, running ? T->a: NULL);
1920 gel(T->a,1) = incloop(gel(T->a,1));
1921 if (done) return done;
1922 }
1923 mt_queue_end(&T->iter.pt);
1924 return NULL;
1925 }
1926
1927 void
parfor_stop(parfor_t * T)1928 parfor_stop(parfor_t *T) { parforiter_stop(&T->iter); }
1929
1930 static long
gp_evalvoid2(void * E,GEN x,GEN y)1931 gp_evalvoid2(void *E, GEN x, GEN y)
1932 {
1933 GEN code =(GEN) E;
1934 push_lex(x, code);
1935 push_lex(y, NULL);
1936 closure_evalvoid(code);
1937 pop_lex(2);
1938 return loop_break();
1939 }
1940
1941 void
parfor0(GEN a,GEN b,GEN code,GEN code2)1942 parfor0(GEN a, GEN b, GEN code, GEN code2)
1943 {
1944 parfor(a, b, code, (void*)code2, code2 ? gp_evalvoid2: NULL);
1945 }
1946
1947 void
parforprimestep_init(parforprime_t * T,GEN a,GEN b,GEN q,GEN code)1948 parforprimestep_init(parforprime_t *T, GEN a, GEN b, GEN q, GEN code)
1949 {
1950 forprimestep_init(&T->forprime, a, b, q);
1951 T->v = mkvec(gen_0);
1952 parforiter_init(&T->iter, code);
1953 }
1954
1955 void
parforprime_init(parforprime_t * T,GEN a,GEN b,GEN code)1956 parforprime_init(parforprime_t *T, GEN a, GEN b, GEN code)
1957 { parforprimestep_init(T, a, b, NULL, code); }
1958
1959 GEN
parforprime_next(parforprime_t * T)1960 parforprime_next(parforprime_t *T)
1961 {
1962 long running;
1963 while ((running = !!forprime_next(&T->forprime)) || T->iter.pending)
1964 {
1965 GEN done;
1966 gel(T->v, 1) = T->forprime.pp;
1967 done = parforiter_next(&T->iter, running ? T->v: NULL);
1968 if (done) return done;
1969 }
1970 mt_queue_end(&T->iter.pt);
1971 return NULL;
1972 }
1973
1974 void
parforprime_stop(parforprime_t * T)1975 parforprime_stop(parforprime_t *T) { parforiter_stop(&T->iter); }
1976
1977 void
parforprimestep(GEN a,GEN b,GEN q,GEN code,void * E,long call (void *,GEN,GEN))1978 parforprimestep(GEN a, GEN b, GEN q, GEN code, void *E, long call(void*, GEN, GEN))
1979 {
1980 pari_sp av = avma, av2;
1981 long running, pending = 0;
1982 long status = br_NONE;
1983 GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));
1984 GEN v, done, stop = NULL;
1985 struct pari_mt pt;
1986 forprime_t T;
1987
1988 if (!forprimestep_init(&T, a,b,q)) { set_avma(av); return; }
1989 mt_queue_start(&pt, worker);
1990 v = mkvec(gen_0);
1991 av2 = avma;
1992 while ((running = (!stop && forprime_next(&T))) || pending)
1993 {
1994 gel(v, 1) = T.pp;
1995 mt_queue_submit(&pt, 0, running ? v: NULL);
1996 done = mt_queue_get(&pt, NULL, &pending);
1997 if (call && done && (!stop || cmpii(gel(done,1),stop) < 0))
1998 if (call(E, gel(done,1), gel(done,2)))
1999 {
2000 status = br_status;
2001 br_status = br_NONE;
2002 stop = gerepileuptoint(av2, gel(done,1));
2003 }
2004 if (!stop) set_avma(av2);
2005 }
2006 set_avma(av2);
2007 mt_queue_end(&pt);
2008 br_status = status;
2009 set_avma(av);
2010 }
2011
2012 void
parforprime(GEN a,GEN b,GEN code,void * E,long call (void *,GEN,GEN))2013 parforprime(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN))
2014 {
2015 parforprimestep(a, b, NULL, code, E, call);
2016 }
2017
2018 void
parforprime0(GEN a,GEN b,GEN code,GEN code2)2019 parforprime0(GEN a, GEN b, GEN code, GEN code2)
2020 {
2021 parforprime(a, b, code, (void*)code2, code2? gp_evalvoid2: NULL);
2022 }
2023
2024 void
parforprimestep0(GEN a,GEN b,GEN q,GEN code,GEN code2)2025 parforprimestep0(GEN a, GEN b, GEN q, GEN code, GEN code2)
2026 {
2027 parforprimestep(a, b, q, code, (void*)code2, code2? gp_evalvoid2: NULL);
2028 }
2029
2030 void
parforvec_init(parforvec_t * T,GEN x,GEN code,long flag)2031 parforvec_init(parforvec_t *T, GEN x, GEN code, long flag)
2032 {
2033 forvec_init(&T->forvec, x, flag);
2034 T->v = mkvec(gen_0);
2035 parforiter_init(&T->iter, code);
2036 }
2037
2038 GEN
parforvec_next(parforvec_t * T)2039 parforvec_next(parforvec_t *T)
2040 {
2041 GEN v = gen_0;
2042 while ((v = forvec_next(&T->forvec)) || T->iter.pending)
2043 {
2044 GEN done;
2045 if (v) gel(T->v, 1) = v;
2046 done = parforiter_next(&T->iter, v ? T->v: NULL);
2047 if (done) return done;
2048 }
2049 mt_queue_end(&T->iter.pt);
2050 return NULL;
2051 }
2052
2053 void
parforvec_stop(parforvec_t * T)2054 parforvec_stop(parforvec_t *T) { parforiter_stop(&T->iter); }
2055
2056 void
parforvec(GEN x,GEN code,long flag,void * E,long call (void *,GEN,GEN))2057 parforvec(GEN x, GEN code, long flag, void *E, long call(void*, GEN, GEN))
2058 {
2059 pari_sp av = avma, av2;
2060 long running, pending = 0;
2061 long status = br_NONE;
2062 GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));
2063 GEN done, stop = NULL;
2064 struct pari_mt pt;
2065 forvec_t T;
2066 GEN a, v = gen_0;
2067
2068 if (!forvec_init(&T, x, flag)) { set_avma(av); return; }
2069 mt_queue_start(&pt, worker);
2070 a = mkvec(gen_0);
2071 av2 = avma;
2072 while ((running = (!stop && v && (v = forvec_next(&T)))) || pending)
2073 {
2074 gel(a, 1) = v;
2075 mt_queue_submit(&pt, 0, running ? a: NULL);
2076 done = mt_queue_get(&pt, NULL, &pending);
2077 if (call && done && (!stop || lexcmp(gel(done,1),stop) < 0))
2078 if (call(E, gel(done,1), gel(done,2)))
2079 {
2080 status = br_status;
2081 br_status = br_NONE;
2082 stop = gerepilecopy(av2, gel(done,1));
2083 }
2084 if (!stop) set_avma(av2);
2085 }
2086 set_avma(av2);
2087 mt_queue_end(&pt);
2088 br_status = status;
2089 set_avma(av);
2090 }
2091
2092 void
parforvec0(GEN x,GEN code,GEN code2,long flag)2093 parforvec0(GEN x, GEN code, GEN code2, long flag)
2094 {
2095 parforvec(x, code, flag, (void*)code2, code2? gp_evalvoid2: NULL);
2096 }
2097
2098 void
parforeach_init(parforeach_t * T,GEN x,GEN code)2099 parforeach_init(parforeach_t *T, GEN x, GEN code)
2100 {
2101 switch(typ(x))
2102 {
2103 case t_LIST:
2104 x = list_data(x); /* FALL THROUGH */
2105 if (!x) return;
2106 case t_MAT: case t_VEC: case t_COL:
2107 break;
2108 default:
2109 pari_err_TYPE("foreach",x);
2110 return; /*LCOV_EXCL_LINE*/
2111 }
2112 T->x = x; T->i = 1; T->l = lg(x);
2113 T->W = mkvec(gen_0);
2114 T->iter.pending = 0;
2115 T->iter.worker = snm_closure(is_entry("_parvector_worker"), mkvec(code));
2116 mt_queue_start(&T->iter.pt, T->iter.worker);
2117 }
2118
2119 GEN
parforeach_next(parforeach_t * T)2120 parforeach_next(parforeach_t *T)
2121 {
2122 while (T->i < T->l || T->iter.pending)
2123 {
2124 GEN done;
2125 long workid;
2126 if (T->i < T->l) gel(T->W,1) = gel(T->x, T->i);
2127 mt_queue_submit(&T->iter.pt, T->i, T->i < T->l ? T->W: NULL);
2128 T->i = minss(T->i+1, T->l);
2129 done = mt_queue_get(&T->iter.pt, &workid, &T->iter.pending);
2130 if (done) return mkvec2(gel(T->x,workid),done);
2131 }
2132 mt_queue_end(&T->iter.pt);
2133 return NULL;
2134 }
2135
2136 void
parforeach_stop(parforeach_t * T)2137 parforeach_stop(parforeach_t *T) { parforiter_stop(&T->iter); }
2138
2139 void
parforeach(GEN x,GEN code,void * E,long call (void *,GEN,GEN))2140 parforeach(GEN x, GEN code, void *E, long call(void*, GEN, GEN))
2141 {
2142 pari_sp av = avma, av2;
2143 long pending = 0, n, i, stop = 0;
2144 long status = br_NONE, workid;
2145 GEN worker = snm_closure(is_entry("_parvector_worker"), mkvec(code));
2146 GEN done, W;
2147 struct pari_mt pt;
2148 switch(typ(x))
2149 {
2150 case t_LIST:
2151 x = list_data(x); /* FALL THROUGH */
2152 if (!x) return;
2153 case t_MAT: case t_VEC: case t_COL:
2154 break;
2155 default:
2156 pari_err_TYPE("foreach",x);
2157 return; /*LCOV_EXCL_LINE*/
2158 }
2159 clone_lock(x); n = lg(x)-1;
2160 mt_queue_start_lim(&pt, worker, n);
2161 W = cgetg(2, t_VEC);
2162 av2 = avma;
2163 for (i=1; i<=n || pending; i++)
2164 {
2165 if (!stop && i <= n) gel(W,1) = gel(x,i);
2166 mt_queue_submit(&pt, i, !stop && i<=n? W: NULL);
2167 done = mt_queue_get(&pt, &workid, &pending);
2168 if (call && done && (!stop || workid < stop))
2169 if (call(E, gel(x, workid), done))
2170 {
2171 status = br_status;
2172 br_status = br_NONE;
2173 stop = workid;
2174 }
2175 }
2176 set_avma(av2);
2177 mt_queue_end(&pt);
2178 br_status = status;
2179 set_avma(av);
2180 }
2181
2182 void
parforeach0(GEN x,GEN code,GEN code2)2183 parforeach0(GEN x, GEN code, GEN code2)
2184 {
2185 parforeach(x, code, (void*)code2, code2? gp_evalvoid2: NULL);
2186 }
2187
2188 void
closure_callvoid1(GEN C,GEN x)2189 closure_callvoid1(GEN C, GEN x)
2190 {
2191 long i, ar = closure_arity(C);
2192 gel(st,sp++) = x;
2193 for(i=2; i <= ar; i++) gel(st,sp++) = NULL;
2194 closure_evalvoid(C);
2195 }
2196
2197 GEN
closure_callgen0prec(GEN C,long prec)2198 closure_callgen0prec(GEN C, long prec)
2199 {
2200 GEN z;
2201 long i, ar = closure_arity(C);
2202 for(i=1; i<= ar; i++) gel(st,sp++) = NULL;
2203 push_localprec(prec);
2204 z = closure_returnupto(C);
2205 pop_localprec();
2206 return z;
2207 }
2208
2209 GEN
closure_callgen1(GEN C,GEN x)2210 closure_callgen1(GEN C, GEN x)
2211 {
2212 long i, ar = closure_arity(C);
2213 gel(st,sp++) = x;
2214 for(i=2; i<= ar; i++) gel(st,sp++) = NULL;
2215 return closure_returnupto(C);
2216 }
2217
2218 GEN
closure_callgen1prec(GEN C,GEN x,long prec)2219 closure_callgen1prec(GEN C, GEN x, long prec)
2220 {
2221 GEN z;
2222 long i, ar = closure_arity(C);
2223 gel(st,sp++) = x;
2224 for(i=2; i<= ar; i++) gel(st,sp++) = NULL;
2225 push_localprec(prec);
2226 z = closure_returnupto(C);
2227 pop_localprec();
2228 return z;
2229 }
2230
2231 GEN
closure_callgen2(GEN C,GEN x,GEN y)2232 closure_callgen2(GEN C, GEN x, GEN y)
2233 {
2234 long i, ar = closure_arity(C);
2235 st_alloc(ar);
2236 gel(st,sp++) = x;
2237 gel(st,sp++) = y;
2238 for(i=3; i<=ar; i++) gel(st,sp++) = NULL;
2239 return closure_returnupto(C);
2240 }
2241
2242 GEN
closure_callgenvec(GEN C,GEN args)2243 closure_callgenvec(GEN C, GEN args)
2244 {
2245 long i, l = lg(args)-1, ar = closure_arity(C);
2246 st_alloc(ar);
2247 if (l > ar)
2248 pari_err(e_MISC,"too many parameters in user-defined function call");
2249 if (closure_is_variadic(C) && l==ar && typ(gel(args,l))!=t_VEC)
2250 pari_err_TYPE("call", gel(args,l));
2251 for (i = 1; i <= l; i++) gel(st,sp++) = gel(args,i);
2252 for( ; i <= ar; i++) gel(st,sp++) = NULL;
2253 return closure_returnupto(C);
2254 }
2255
2256 GEN
closure_callgenvecprec(GEN C,GEN args,long prec)2257 closure_callgenvecprec(GEN C, GEN args, long prec)
2258 {
2259 GEN z;
2260 push_localprec(prec);
2261 z = closure_callgenvec(C, args);
2262 pop_localprec();
2263 return z;
2264 }
2265
2266 GEN
closure_callgenvecdef(GEN C,GEN args,GEN def)2267 closure_callgenvecdef(GEN C, GEN args, GEN def)
2268 {
2269 long i, l = lg(args)-1, ar = closure_arity(C);
2270 st_alloc(ar);
2271 if (l > ar)
2272 pari_err(e_MISC,"too many parameters in user-defined function call");
2273 if (closure_is_variadic(C) && l==ar && typ(gel(args,l))!=t_VEC)
2274 pari_err_TYPE("call", gel(args,l));
2275 for (i = 1; i <= l; i++) gel(st,sp++) = def[i] ? gel(args,i): NULL;
2276 for( ; i <= ar; i++) gel(st,sp++) = NULL;
2277 return closure_returnupto(C);
2278 }
2279
2280 GEN
closure_callgenvecdefprec(GEN C,GEN args,GEN def,long prec)2281 closure_callgenvecdefprec(GEN C, GEN args, GEN def, long prec)
2282 {
2283 GEN z;
2284 push_localprec(prec);
2285 z = closure_callgenvecdef(C, args, def);
2286 pop_localprec();
2287 return z;
2288 }
2289 GEN
closure_callgenall(GEN C,long n,...)2290 closure_callgenall(GEN C, long n, ...)
2291 {
2292 va_list ap;
2293 long i, ar = closure_arity(C);
2294 va_start(ap,n);
2295 if (n > ar)
2296 pari_err(e_MISC,"too many parameters in user-defined function call");
2297 st_alloc(ar);
2298 for (i = 1; i <=n; i++) gel(st,sp++) = va_arg(ap, GEN);
2299 for( ; i <=ar; i++) gel(st,sp++) = NULL;
2300 va_end(ap);
2301 return closure_returnupto(C);
2302 }
2303
2304 GEN
gp_eval(void * E,GEN x)2305 gp_eval(void *E, GEN x)
2306 {
2307 GEN code = (GEN)E;
2308 set_lex(-1,x);
2309 return closure_evalnobrk(code);
2310 }
2311
2312 GEN
gp_evalupto(void * E,GEN x)2313 gp_evalupto(void *E, GEN x)
2314 {
2315 pari_sp av = avma;
2316 return copyupto(gp_eval(E,x), (GEN)av);
2317 }
2318
2319 GEN
gp_evalprec(void * E,GEN x,long prec)2320 gp_evalprec(void *E, GEN x, long prec)
2321 {
2322 GEN z;
2323 push_localprec(prec);
2324 z = gp_eval(E, x);
2325 pop_localprec();
2326 return z;
2327 }
2328
2329 long
gp_evalbool(void * E,GEN x)2330 gp_evalbool(void *E, GEN x)
2331 { pari_sp av = avma; return gc_long(av, !gequal0(gp_eval(E,x))); }
2332
2333 long
gp_evalvoid(void * E,GEN x)2334 gp_evalvoid(void *E, GEN x)
2335 {
2336 GEN code = (GEN)E;
2337 set_lex(-1,x);
2338 closure_evalvoid(code);
2339 return loop_break();
2340 }
2341
2342 GEN
gp_call(void * E,GEN x)2343 gp_call(void *E, GEN x)
2344 {
2345 GEN code = (GEN)E;
2346 return closure_callgen1(code, x);
2347 }
2348
2349 GEN
gp_callprec(void * E,GEN x,long prec)2350 gp_callprec(void *E, GEN x, long prec)
2351 {
2352 GEN code = (GEN)E;
2353 return closure_callgen1prec(code, x, prec);
2354 }
2355
2356 GEN
gp_call2(void * E,GEN x,GEN y)2357 gp_call2(void *E, GEN x, GEN y)
2358 {
2359 GEN code = (GEN)E;
2360 return closure_callgen2(code, x, y);
2361 }
2362
2363 long
gp_callbool(void * E,GEN x)2364 gp_callbool(void *E, GEN x)
2365 {
2366 pari_sp av = avma;
2367 GEN code = (GEN)E;
2368 return gc_long(av, !gequal0(closure_callgen1(code, x)));
2369 }
2370
2371 long
gp_callvoid(void * E,GEN x)2372 gp_callvoid(void *E, GEN x)
2373 {
2374 GEN code = (GEN)E;
2375 closure_callvoid1(code, x);
2376 return loop_break();
2377 }
2378
2379 INLINE const char *
disassemble_cast(long mode)2380 disassemble_cast(long mode)
2381 {
2382 switch (mode)
2383 {
2384 case Gsmall:
2385 return "small";
2386 case Ggen:
2387 return "gen";
2388 case Gvar:
2389 return "var";
2390 case Gvoid:
2391 return "void";
2392 default:
2393 return "unknown";
2394 }
2395 }
2396
2397 void
closure_disassemble(GEN C)2398 closure_disassemble(GEN C)
2399 {
2400 const char * code;
2401 GEN oper;
2402 long i;
2403 if (typ(C)!=t_CLOSURE) pari_err_TYPE("disassemble",C);
2404 code=closure_codestr(C);
2405 oper=closure_get_oper(C);
2406 for(i=1;i<lg(oper);i++)
2407 {
2408 op_code opcode=(op_code) code[i];
2409 long operand=oper[i];
2410 pari_printf("%05ld\t",i);
2411 switch(opcode)
2412 {
2413 case OCpushlong:
2414 pari_printf("pushlong\t%ld\n",operand);
2415 break;
2416 case OCpushgnil:
2417 pari_printf("pushgnil\n");
2418 break;
2419 case OCpushgen:
2420 pari_printf("pushgen\t\t%ld\n",operand);
2421 break;
2422 case OCpushreal:
2423 pari_printf("pushreal\t%ld\n",operand);
2424 break;
2425 case OCpushstoi:
2426 pari_printf("pushstoi\t%ld\n",operand);
2427 break;
2428 case OCpushvar:
2429 {
2430 entree *ep = (entree *)operand;
2431 pari_printf("pushvar\t%s\n",ep->name);
2432 break;
2433 }
2434 case OCpushdyn:
2435 {
2436 entree *ep = (entree *)operand;
2437 pari_printf("pushdyn\t\t%s\n",ep->name);
2438 break;
2439 }
2440 case OCpushlex:
2441 pari_printf("pushlex\t\t%ld\n",operand);
2442 break;
2443 case OCstoredyn:
2444 {
2445 entree *ep = (entree *)operand;
2446 pari_printf("storedyn\t%s\n",ep->name);
2447 break;
2448 }
2449 case OCstorelex:
2450 pari_printf("storelex\t%ld\n",operand);
2451 break;
2452 case OCstoreptr:
2453 pari_printf("storeptr\n");
2454 break;
2455 case OCsimpleptrdyn:
2456 {
2457 entree *ep = (entree *)operand;
2458 pari_printf("simpleptrdyn\t%s\n",ep->name);
2459 break;
2460 }
2461 case OCsimpleptrlex:
2462 pari_printf("simpleptrlex\t%ld\n",operand);
2463 break;
2464 case OCnewptrdyn:
2465 {
2466 entree *ep = (entree *)operand;
2467 pari_printf("newptrdyn\t%s\n",ep->name);
2468 break;
2469 }
2470 case OCnewptrlex:
2471 pari_printf("newptrlex\t%ld\n",operand);
2472 break;
2473 case OCpushptr:
2474 pari_printf("pushptr\n");
2475 break;
2476 case OCstackgen:
2477 pari_printf("stackgen\t%ld\n",operand);
2478 break;
2479 case OCendptr:
2480 pari_printf("endptr\t\t%ld\n",operand);
2481 break;
2482 case OCprecreal:
2483 pari_printf("precreal\n");
2484 break;
2485 case OCbitprecreal:
2486 pari_printf("bitprecreal\n");
2487 break;
2488 case OCprecdl:
2489 pari_printf("precdl\n");
2490 break;
2491 case OCstoi:
2492 pari_printf("stoi\n");
2493 break;
2494 case OCutoi:
2495 pari_printf("utoi\n");
2496 break;
2497 case OCitos:
2498 pari_printf("itos\t\t%ld\n",operand);
2499 break;
2500 case OCitou:
2501 pari_printf("itou\t\t%ld\n",operand);
2502 break;
2503 case OCtostr:
2504 pari_printf("tostr\t\t%ld\n",operand);
2505 break;
2506 case OCvarn:
2507 pari_printf("varn\t\t%ld\n",operand);
2508 break;
2509 case OCcopy:
2510 pari_printf("copy\n");
2511 break;
2512 case OCcopyifclone:
2513 pari_printf("copyifclone\n");
2514 break;
2515 case OCcompo1:
2516 pari_printf("compo1\t\t%s\n",disassemble_cast(operand));
2517 break;
2518 case OCcompo1ptr:
2519 pari_printf("compo1ptr\n");
2520 break;
2521 case OCcompo2:
2522 pari_printf("compo2\t\t%s\n",disassemble_cast(operand));
2523 break;
2524 case OCcompo2ptr:
2525 pari_printf("compo2ptr\n");
2526 break;
2527 case OCcompoC:
2528 pari_printf("compoC\n");
2529 break;
2530 case OCcompoCptr:
2531 pari_printf("compoCptr\n");
2532 break;
2533 case OCcompoL:
2534 pari_printf("compoL\n");
2535 break;
2536 case OCcompoLptr:
2537 pari_printf("compoLptr\n");
2538 break;
2539 case OCcheckargs:
2540 pari_printf("checkargs\t0x%lx\n",operand);
2541 break;
2542 case OCcheckargs0:
2543 pari_printf("checkargs0\t0x%lx\n",operand);
2544 break;
2545 case OCcheckuserargs:
2546 pari_printf("checkuserargs\t%ld\n",operand);
2547 break;
2548 case OCdefaultlong:
2549 pari_printf("defaultlong\t%ld\n",operand);
2550 break;
2551 case OCdefaultulong:
2552 pari_printf("defaultulong\t%ld\n",operand);
2553 break;
2554 case OCdefaultgen:
2555 pari_printf("defaultgen\t%ld\n",operand);
2556 break;
2557 case OCpackargs:
2558 pari_printf("packargs\t%ld\n",operand);
2559 break;
2560 case OCgetargs:
2561 pari_printf("getargs\t\t%ld\n",operand);
2562 break;
2563 case OCdefaultarg:
2564 pari_printf("defaultarg\t%ld\n",operand);
2565 break;
2566 case OClocalvar:
2567 {
2568 entree *ep = (entree *)operand;
2569 pari_printf("localvar\t%s\n",ep->name);
2570 break;
2571 }
2572 case OClocalvar0:
2573 {
2574 entree *ep = (entree *)operand;
2575 pari_printf("localvar0\t%s\n",ep->name);
2576 break;
2577 }
2578 case OCexportvar:
2579 {
2580 entree *ep = (entree *)operand;
2581 pari_printf("exportvar\t%s\n",ep->name);
2582 break;
2583 }
2584 case OCunexportvar:
2585 {
2586 entree *ep = (entree *)operand;
2587 pari_printf("unexportvar\t%s\n",ep->name);
2588 break;
2589 }
2590 case OCcallgen:
2591 {
2592 entree *ep = (entree *)operand;
2593 pari_printf("callgen\t\t%s\n",ep->name);
2594 break;
2595 }
2596 case OCcallgen2:
2597 {
2598 entree *ep = (entree *)operand;
2599 pari_printf("callgen2\t%s\n",ep->name);
2600 break;
2601 }
2602 case OCcalllong:
2603 {
2604 entree *ep = (entree *)operand;
2605 pari_printf("calllong\t%s\n",ep->name);
2606 break;
2607 }
2608 case OCcallint:
2609 {
2610 entree *ep = (entree *)operand;
2611 pari_printf("callint\t\t%s\n",ep->name);
2612 break;
2613 }
2614 case OCcallvoid:
2615 {
2616 entree *ep = (entree *)operand;
2617 pari_printf("callvoid\t%s\n",ep->name);
2618 break;
2619 }
2620 case OCcalluser:
2621 pari_printf("calluser\t%ld\n",operand);
2622 break;
2623 case OCvec:
2624 pari_printf("vec\t\t%ld\n",operand);
2625 break;
2626 case OCcol:
2627 pari_printf("col\t\t%ld\n",operand);
2628 break;
2629 case OCmat:
2630 pari_printf("mat\t\t%ld\n",operand);
2631 break;
2632 case OCnewframe:
2633 pari_printf("newframe\t%ld\n",operand);
2634 break;
2635 case OCsaveframe:
2636 pari_printf("saveframe\t%ld\n", operand);
2637 break;
2638 case OCpop:
2639 pari_printf("pop\t\t%ld\n",operand);
2640 break;
2641 case OCdup:
2642 pari_printf("dup\t\t%ld\n",operand);
2643 break;
2644 case OCavma:
2645 pari_printf("avma\n",operand);
2646 break;
2647 case OCgerepile:
2648 pari_printf("gerepile\n",operand);
2649 break;
2650 case OCcowvardyn:
2651 {
2652 entree *ep = (entree *)operand;
2653 pari_printf("cowvardyn\t%s\n",ep->name);
2654 break;
2655 }
2656 case OCcowvarlex:
2657 pari_printf("cowvarlex\t%ld\n",operand);
2658 break;
2659 case OCsetref:
2660 pari_printf("setref\t\t%ld\n",operand);
2661 break;
2662 case OClock:
2663 pari_printf("lock\t\t%ld\n",operand);
2664 break;
2665 }
2666 }
2667 }
2668
2669 static int
opcode_need_relink(op_code opcode)2670 opcode_need_relink(op_code opcode)
2671 {
2672 switch(opcode)
2673 {
2674 case OCpushlong:
2675 case OCpushgen:
2676 case OCpushgnil:
2677 case OCpushreal:
2678 case OCpushstoi:
2679 case OCpushlex:
2680 case OCstorelex:
2681 case OCstoreptr:
2682 case OCsimpleptrlex:
2683 case OCnewptrlex:
2684 case OCpushptr:
2685 case OCstackgen:
2686 case OCendptr:
2687 case OCprecreal:
2688 case OCbitprecreal:
2689 case OCprecdl:
2690 case OCstoi:
2691 case OCutoi:
2692 case OCitos:
2693 case OCitou:
2694 case OCtostr:
2695 case OCvarn:
2696 case OCcopy:
2697 case OCcopyifclone:
2698 case OCcompo1:
2699 case OCcompo1ptr:
2700 case OCcompo2:
2701 case OCcompo2ptr:
2702 case OCcompoC:
2703 case OCcompoCptr:
2704 case OCcompoL:
2705 case OCcompoLptr:
2706 case OCcheckargs:
2707 case OCcheckargs0:
2708 case OCcheckuserargs:
2709 case OCpackargs:
2710 case OCgetargs:
2711 case OCdefaultarg:
2712 case OCdefaultgen:
2713 case OCdefaultlong:
2714 case OCdefaultulong:
2715 case OCcalluser:
2716 case OCvec:
2717 case OCcol:
2718 case OCmat:
2719 case OCnewframe:
2720 case OCsaveframe:
2721 case OCdup:
2722 case OCpop:
2723 case OCavma:
2724 case OCgerepile:
2725 case OCcowvarlex:
2726 case OCsetref:
2727 case OClock:
2728 break;
2729 case OCpushvar:
2730 case OCpushdyn:
2731 case OCstoredyn:
2732 case OCsimpleptrdyn:
2733 case OCnewptrdyn:
2734 case OClocalvar:
2735 case OClocalvar0:
2736 case OCexportvar:
2737 case OCunexportvar:
2738 case OCcallgen:
2739 case OCcallgen2:
2740 case OCcalllong:
2741 case OCcallint:
2742 case OCcallvoid:
2743 case OCcowvardyn:
2744 return 1;
2745 }
2746 return 0;
2747 }
2748
2749 static void
closure_relink(GEN C,hashtable * table)2750 closure_relink(GEN C, hashtable *table)
2751 {
2752 const char *code = closure_codestr(C);
2753 GEN oper = closure_get_oper(C);
2754 GEN fram = gel(closure_get_dbg(C),3);
2755 long i, j;
2756 for(i=1;i<lg(oper);i++)
2757 if (oper[i] && opcode_need_relink((op_code)code[i]))
2758 oper[i] = (long) hash_search(table,(void*) oper[i])->val;
2759 for (i=1;i<lg(fram);i++)
2760 for (j=1;j<lg(gel(fram,i));j++)
2761 if (mael(fram,i,j))
2762 mael(fram,i,j) = (long) hash_search(table,(void*) mael(fram,i,j))->val;
2763 }
2764
2765 void
gen_relink(GEN x,hashtable * table)2766 gen_relink(GEN x, hashtable *table)
2767 {
2768 long i, lx, tx = typ(x);
2769 switch(tx)
2770 {
2771 case t_CLOSURE:
2772 closure_relink(x, table);
2773 gen_relink(closure_get_data(x), table);
2774 if (lg(x)==8) gen_relink(closure_get_frame(x), table);
2775 break;
2776 case t_LIST:
2777 if (list_data(x)) gen_relink(list_data(x), table);
2778 break;
2779 case t_VEC: case t_COL: case t_MAT: case t_ERROR:
2780 lx = lg(x);
2781 for (i=lontyp[tx]; i<lx; i++) gen_relink(gel(x,i), table);
2782 }
2783 }
2784
2785 static void
closure_unlink(GEN C)2786 closure_unlink(GEN C)
2787 {
2788 const char *code = closure_codestr(C);
2789 GEN oper = closure_get_oper(C);
2790 GEN fram = gel(closure_get_dbg(C),3);
2791 long i, j;
2792 for(i=1;i<lg(oper);i++)
2793 if (oper[i] && opcode_need_relink((op_code) code[i]))
2794 {
2795 long n = pari_stack_new(&s_relocs);
2796 relocs[n] = (entree *) oper[i];
2797 }
2798 for (i=1;i<lg(fram);i++)
2799 for (j=1;j<lg(gel(fram,i));j++)
2800 if (mael(fram,i,j))
2801 {
2802 long n = pari_stack_new(&s_relocs);
2803 relocs[n] = (entree *) mael(fram,i,j);
2804 }
2805 }
2806
2807 static void
gen_unlink(GEN x)2808 gen_unlink(GEN x)
2809 {
2810 long i, lx, tx = typ(x);
2811 switch(tx)
2812 {
2813 case t_CLOSURE:
2814 closure_unlink(x);
2815 gen_unlink(closure_get_data(x));
2816 if (lg(x)==8) gen_unlink(closure_get_frame(x));
2817 break;
2818 case t_LIST:
2819 if (list_data(x)) gen_unlink(list_data(x));
2820 break;
2821 case t_VEC: case t_COL: case t_MAT: case t_ERROR:
2822 lx = lg(x);
2823 for (i = lontyp[tx]; i<lx; i++) gen_unlink(gel(x,i));
2824 }
2825 }
2826
2827 GEN
copybin_unlink(GEN C)2828 copybin_unlink(GEN C)
2829 {
2830 long i, l , n, nold = s_relocs.n;
2831 GEN v, w, V, res;
2832 if (C)
2833 gen_unlink(C);
2834 else
2835 { /* contents of all variables */
2836 long v, maxv = pari_var_next();
2837 for (v=0; v<maxv; v++)
2838 {
2839 entree *ep = varentries[v];
2840 if (!ep || !ep->value) continue;
2841 gen_unlink((GEN)ep->value);
2842 }
2843 }
2844 n = s_relocs.n-nold;
2845 v = cgetg(n+1, t_VECSMALL);
2846 for(i=0; i<n; i++)
2847 v[i+1] = (long) relocs[i];
2848 s_relocs.n = nold;
2849 w = vecsmall_uniq(v); l = lg(w);
2850 res = cgetg(3,t_VEC);
2851 V = cgetg(l, t_VEC);
2852 for(i=1; i<l; i++)
2853 {
2854 entree *ep = (entree*) w[i];
2855 gel(V,i) = strtoGENstr(ep->name);
2856 }
2857 gel(res,1) = vecsmall_copy(w);
2858 gel(res,2) = V;
2859 return res;
2860 }
2861
2862 /* e = t_VECSMALL of entree *ep [ addresses ],
2863 * names = t_VEC of strtoGENstr(ep.names),
2864 * Return hashtable : ep => is_entry(ep.name) */
2865 hashtable *
hash_from_link(GEN e,GEN names,int use_stack)2866 hash_from_link(GEN e, GEN names, int use_stack)
2867 {
2868 long i, l = lg(e);
2869 hashtable *h = hash_create_ulong(l-1, use_stack);
2870 if (lg(names) != l) pari_err_DIM("hash_from_link");
2871 for (i = 1; i < l; i++)
2872 {
2873 char *s = GSTR(gel(names,i));
2874 hash_insert(h, (void*)e[i], (void*)fetch_entry(s));
2875 }
2876 return h;
2877 }
2878
2879 void
bincopy_relink(GEN C,GEN V)2880 bincopy_relink(GEN C, GEN V)
2881 {
2882 pari_sp av = avma;
2883 hashtable *table = hash_from_link(gel(V,1),gel(V,2),1);
2884 gen_relink(C, table);
2885 set_avma(av);
2886 }
2887