Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

Testing latest pari + WASM + node.js... and it works?! Wow.

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