Testing latest pari + WASM + node.js... and it works?! Wow.
License: GPL3
ubuntu2004
/* Copyright (C) 2006 The PARI group.12This file is part of the PARI package.34PARI/GP is free software; you can redistribute it and/or modify it under the5terms of the GNU General Public License as published by the Free Software6Foundation; either version 2 of the License, or (at your option) any later7version. It is distributed in the hope that it will be useful, but WITHOUT8ANY WARRANTY WHATSOEVER.910Check the License for details. You should have received a copy of it, along11with the package; see the file 'COPYING'. If not, write to the Free Software12Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */1314#include "pari.h"15#include "paripriv.h"16#include "anal.h"17#include "opcode.h"1819/********************************************************************/20/* */21/* break/next/return handling */22/* */23/********************************************************************/2425static THREAD long br_status, br_count;26static THREAD GEN br_res;2728long29loop_break(void)30{31switch(br_status)32{33case br_MULTINEXT :34if (! --br_count) br_status = br_NEXT;35return 1;36case br_BREAK : if (! --br_count) br_status = br_NONE; /* fall through */37case br_RETURN: return 1;38case br_NEXT: br_status = br_NONE; /* fall through */39}40return 0;41}4243static void44reset_break(void)45{46br_status = br_NONE;47if (br_res) { gunclone_deep(br_res); br_res = NULL; }48}4950GEN51return0(GEN x)52{53GEN y = br_res;54br_res = (x && x != gnil)? gcloneref(x): NULL;55guncloneNULL_deep(y);56br_status = br_RETURN; return NULL;57}5859GEN60next0(long n)61{62if (n < 1) pari_err_DOMAIN("next", "n", "<", gen_1, stoi(n));63if (n == 1) br_status = br_NEXT;64else65{66br_count = n-1;67br_status = br_MULTINEXT;68}69return NULL;70}7172GEN73break0(long n)74{75if (n < 1) pari_err_DOMAIN("break", "n", "<", gen_1, stoi(n));76br_count = n;77br_status = br_BREAK; return NULL;78}7980/*******************************************************************/81/* */82/* VARIABLES */83/* */84/*******************************************************************/8586/* As a rule, ep->value is a clone (COPY). push_val and pop_val are private87* functions for use in sumiter: we want a temporary ep->value, which is NOT88* a clone (PUSH), to avoid unnecessary copies. */8990enum {PUSH_VAL = 0, COPY_VAL = 1, DEFAULT_VAL = 2, REF_VAL = 3};9192/* ep->args is the stack of old values (INITIAL if initial value, from93* installep) */94typedef struct var_cell {95struct var_cell *prev; /* cell attached to previous value on stack */96GEN value; /* last value (not including current one, in ep->value) */97char flag; /* status of _current_ ep->value: PUSH or COPY ? */98long valence; /* valence of entree* attached to 'value', to be restored99* by pop_val */100} var_cell;101#define INITIAL NULL102103/* Push x on value stack attached to ep. */104static void105new_val_cell(entree *ep, GEN x, char flag)106{107var_cell *v = (var_cell*) pari_malloc(sizeof(var_cell));108v->value = (GEN)ep->value;109v->prev = (var_cell*) ep->pvalue;110v->flag = flag;111v->valence= ep->valence;112113/* beware: f(p) = Nv = 0114* Nv = p; f(Nv) --> this call would destroy p [ isclone ] */115ep->value = (flag == COPY_VAL)? gclone(x):116(x && isclone(x))? gcopy(x): x;117/* Do this last. In case the clone is <C-C>'ed before completion ! */118ep->pvalue= (char*)v;119ep->valence=EpVAR;120}121122/* kill ep->value and replace by preceding one, poped from value stack */123static void124pop_val(entree *ep)125{126var_cell *v = (var_cell*) ep->pvalue;127if (v != INITIAL)128{129GEN old_val = (GEN) ep->value; /* protect against SIGINT */130ep->value = v->value;131if (v->flag == COPY_VAL) gunclone_deep(old_val);132ep->pvalue = (char*) v->prev;133ep->valence=v->valence;134pari_free((void*)v);135}136}137138void139freeep(entree *ep)140{141if (EpSTATIC(ep)) return; /* gp function loaded at init time */142if (ep->help) {pari_free((void*)ep->help); ep->help=NULL;}143if (ep->code) {pari_free((void*)ep->code); ep->code=NULL;}144switch(EpVALENCE(ep))145{146case EpVAR:147while (ep->pvalue!=INITIAL) pop_val(ep);148break;149case EpALIAS:150killblock((GEN)ep->value); ep->value=NULL; break;151}152}153154INLINE void155pushvalue(entree *ep, GEN x) {156new_val_cell(ep, x, COPY_VAL);157}158159INLINE void160zerovalue(entree *ep)161{162var_cell *v = (var_cell*) pari_malloc(sizeof(var_cell));163v->value = (GEN)ep->value;164v->prev = (var_cell*) ep->pvalue;165v->flag = PUSH_VAL;166v->valence= ep->valence;167ep->value = gen_0;168ep->pvalue= (char*)v;169ep->valence=EpVAR;170}171172/* as above IF ep->value was PUSHed, or was created after block number 'loc'173return 0 if not deleted, 1 otherwise [for recover()] */174int175pop_val_if_newer(entree *ep, long loc)176{177var_cell *v = (var_cell*) ep->pvalue;178179if (v == INITIAL) return 0;180if (v->flag == COPY_VAL && !pop_entree_block(ep, loc)) return 0;181ep->value = v->value;182ep->pvalue= (char*) v->prev;183ep->valence=v->valence;184pari_free((void*)v); return 1;185}186187/* set new value of ep directly to val (COPY), do not save last value unless188* it's INITIAL. */189void190changevalue(entree *ep, GEN x)191{192var_cell *v = (var_cell*) ep->pvalue;193if (v == INITIAL) new_val_cell(ep, x, COPY_VAL);194else195{196GEN old_val = (GEN) ep->value; /* beware: gunclone_deep may destroy old x */197ep->value = (void *) gclone(x);198if (v->flag == COPY_VAL) gunclone_deep(old_val); else v->flag = COPY_VAL;199}200}201202INLINE GEN203copyvalue(entree *ep)204{205var_cell *v = (var_cell*) ep->pvalue;206if (v && v->flag != COPY_VAL)207{208ep->value = (void*) gclone((GEN)ep->value);209v->flag = COPY_VAL;210}211return (GEN) ep->value;212}213214INLINE void215err_var(GEN x) { pari_err_TYPE("evaluator [variable name expected]", x); }216217enum chk_VALUE { chk_ERROR, chk_NOCREATE, chk_CREATE };218219INLINE void220checkvalue(entree *ep, enum chk_VALUE flag)221{222if (mt_is_thread())223pari_err(e_MISC,"mt: attempt to change exported variable '%s'",ep->name);224if (ep->valence==EpNEW)225switch(flag)226{227case chk_ERROR:228/* Do nothing until we can report a meaningful error message229The extra variable will be cleaned-up anyway */230case chk_CREATE:231pari_var_create(ep);232ep->valence = EpVAR;233ep->value = initial_value(ep);234break;235case chk_NOCREATE:236break;237}238else if (ep->valence!=EpVAR)239pari_err(e_MISC, "attempt to change built-in %s", ep->name);240}241242INLINE GEN243checkvalueptr(entree *ep)244{245checkvalue(ep, chk_NOCREATE);246return ep->valence==EpNEW? gen_0: (GEN)ep->value;247}248249/* make GP variables safe for set_avma(top) */250static void251lvar_make_safe(void)252{253long n;254entree *ep;255for (n = 0; n < functions_tblsz; n++)256for (ep = functions_hash[n]; ep; ep = ep->next)257if (EpVALENCE(ep) == EpVAR)258{ /* make sure ep->value is a COPY */259var_cell *v = (var_cell*)ep->pvalue;260if (v && v->flag == PUSH_VAL) {261GEN x = (GEN)ep->value;262if (x) changevalue(ep, (GEN)ep->value); else pop_val(ep);263}264}265}266267static void268check_array_index(long c, long l)269{270if (c < 1) pari_err_COMPONENT("", "<", gen_1, stoi(c));271if (c >= l) pari_err_COMPONENT("", ">", stoi(l-1), stoi(c));272}273274GEN*275safegel(GEN x, long l)276{277if (!is_matvec_t(typ(x)))278pari_err_TYPE("safegel",x);279check_array_index(l, lg(x));280return &(gel(x,l));281}282283GEN*284safelistel(GEN x, long l)285{286GEN d;287if (typ(x)!=t_LIST || list_typ(x)!=t_LIST_RAW)288pari_err_TYPE("safelistel",x);289d = list_data(x);290check_array_index(l, lg(d));291return &(gel(d,l));292}293294long*295safeel(GEN x, long l)296{297if (typ(x)!=t_VECSMALL)298pari_err_TYPE("safeel",x);299check_array_index(l, lg(x));300return &(x[l]);301}302303GEN*304safegcoeff(GEN x, long a, long b)305{306if (typ(x)!=t_MAT) pari_err_TYPE("safegcoeff", x);307check_array_index(b, lg(x));308check_array_index(a, lg(gel(x,b)));309return &(gcoeff(x,a,b));310}311312typedef struct matcomp313{314GEN *ptcell;315GEN parent;316int full_col, full_row;317} matcomp;318319typedef struct gp_pointer320{321matcomp c;322GEN x, ox;323entree *ep;324long vn;325long sp;326} gp_pointer;327328/* assign res at *pt in "simple array object" p and return it, or a copy.*/329static void330change_compo(matcomp *c, GEN res)331{332GEN p = c->parent, *pt = c->ptcell;333long i, t;334335if (typ(p) == t_VECSMALL)336{337if (typ(res) != t_INT || is_bigint(res))338pari_err_TYPE("t_VECSMALL assignment", res);339*pt = (GEN)itos(res); return;340}341t = typ(res);342if (c->full_row)343{344if (t != t_VEC) pari_err_TYPE("matrix row assignment", res);345if (lg(res) != lg(p)) pari_err_DIM("matrix row assignment");346for (i=1; i<lg(p); i++)347{348GEN p1 = gcoeff(p,c->full_row,i); /* Protect against SIGINT */349gcoeff(p,c->full_row,i) = gclone(gel(res,i));350if (isclone(p1)) gunclone_deep(p1);351}352return;353}354if (c->full_col)355{356if (t != t_COL) pari_err_TYPE("matrix col assignment", res);357if (lg(res) != lg(*pt)) pari_err_DIM("matrix col assignment");358}359360res = gclone(res);361gunclone_deep(*pt);362*pt = res;363}364365/***************************************************************************366** **367** Byte-code evaluator **368** **369***************************************************************************/370371struct var_lex372{373long flag;374GEN value;375};376377struct trace378{379long pc;380GEN closure;381};382383static THREAD long sp, rp, dbg_level;384static THREAD long *st, *precs;385static THREAD GEN *locks;386static THREAD gp_pointer *ptrs;387static THREAD entree **lvars;388static THREAD struct var_lex *var;389static THREAD struct trace *trace;390static THREAD pari_stack s_st, s_ptrs, s_var, s_trace, s_prec;391static THREAD pari_stack s_lvars, s_locks;392393static void394changelex(long vn, GEN x)395{396struct var_lex *v=var+s_var.n+vn;397GEN old_val = v->value;398v->value = gclone(x);399if (v->flag == COPY_VAL) gunclone_deep(old_val); else v->flag = COPY_VAL;400}401402INLINE GEN403copylex(long vn)404{405struct var_lex *v = var+s_var.n+vn;406if (v->flag!=COPY_VAL && v->flag!=REF_VAL)407{408v->value = gclone(v->value);409v->flag = COPY_VAL;410}411return v->value;412}413414INLINE void415setreflex(long vn)416{417struct var_lex *v = var+s_var.n+vn;418v->flag = REF_VAL;419}420421INLINE void422pushlex(long vn, GEN x)423{424struct var_lex *v=var+s_var.n+vn;425v->flag = PUSH_VAL;426v->value = x;427}428429INLINE void430freelex(void)431{432struct var_lex *v=var+s_var.n-1;433s_var.n--;434if (v->flag == COPY_VAL) gunclone_deep(v->value);435}436437INLINE void438restore_vars(long nbmvar, long nblvar, long nblock)439{440long j;441for(j=1; j<=nbmvar; j++) freelex();442for(j=1; j<=nblvar; j++) { s_lvars.n--; pop_val(lvars[s_lvars.n]); }443for(j=1; j<=nblock; j++) { s_locks.n--; gunclone(locks[s_locks.n]); }444}445446INLINE void447restore_trace(long nbtrace)448{449long j;450for(j=1; j<=nbtrace; j++)451{452GEN C = trace[s_trace.n-j].closure;453clone_unlock(C);454}455s_trace.n -= nbtrace;456}457458INLINE long459trace_push(long pc, GEN C)460{461long tr;462BLOCK_SIGINT_START463tr = pari_stack_new(&s_trace);464trace[tr].pc = pc;465clone_lock(C);466trace[tr].closure = C;467BLOCK_SIGINT_END468return tr;469}470471void472push_lex(GEN a, GEN C)473{474long vn=pari_stack_new(&s_var);475struct var_lex *v=var+vn;476v->flag = PUSH_VAL;477v->value = a;478if (C) (void) trace_push(-1, C);479}480481GEN482get_lex(long vn)483{484struct var_lex *v=var+s_var.n+vn;485return v->value;486}487488void489set_lex(long vn, GEN x)490{491struct var_lex *v=var+s_var.n+vn;492if (v->flag == COPY_VAL) { gunclone_deep(v->value); v->flag = PUSH_VAL; }493v->value = x;494}495496void497pop_lex(long n)498{499long j;500for(j=1; j<=n; j++)501freelex();502s_trace.n--;503}504505static THREAD pari_stack s_relocs;506static THREAD entree **relocs;507508void509pari_init_evaluator(void)510{511sp=0;512pari_stack_init(&s_st,sizeof(*st),(void**)&st);513pari_stack_alloc(&s_st,32);514s_st.n=s_st.alloc;515rp=0;516pari_stack_init(&s_ptrs,sizeof(*ptrs),(void**)&ptrs);517pari_stack_alloc(&s_ptrs,16);518s_ptrs.n=s_ptrs.alloc;519pari_stack_init(&s_var,sizeof(*var),(void**)&var);520pari_stack_init(&s_lvars,sizeof(*lvars),(void**)&lvars);521pari_stack_init(&s_locks,sizeof(*locks),(void**)&locks);522pari_stack_init(&s_trace,sizeof(*trace),(void**)&trace);523br_res = NULL;524pari_stack_init(&s_relocs,sizeof(*relocs),(void**)&relocs);525pari_stack_init(&s_prec,sizeof(*precs),(void**)&precs);526}527void528pari_close_evaluator(void)529{530pari_stack_delete(&s_st);531pari_stack_delete(&s_ptrs);532pari_stack_delete(&s_var);533pari_stack_delete(&s_lvars);534pari_stack_delete(&s_trace);535pari_stack_delete(&s_relocs);536pari_stack_delete(&s_prec);537}538539static gp_pointer *540new_ptr(void)541{542if (rp==s_ptrs.n-1)543{544long i;545gp_pointer *old = ptrs;546(void)pari_stack_new(&s_ptrs);547if (old != ptrs)548for(i=0; i<rp; i++)549{550gp_pointer *g = &ptrs[i];551if(g->sp >= 0) gel(st,g->sp) = (GEN) &(g->x);552}553}554return &ptrs[rp++];555}556557void558push_localbitprec(long p)559{560long n = pari_stack_new(&s_prec);561precs[n] = p;562}563void564push_localprec(long p) { push_localbitprec(prec2nbits(p)); }565566void567pop_localprec(void) { s_prec.n--; }568569long570get_localbitprec(void) { return s_prec.n? precs[s_prec.n-1]: precreal; }571572long573get_localprec(void) { return nbits2prec(get_localbitprec()); }574575static void576checkprec(const char *f, long p, long M)577{578if (p < 1) pari_err_DOMAIN(f, "p", "<", gen_1, stoi(p));579if (p > M) pari_err_DOMAIN(f, "p", ">", utoipos(M), utoi(p));580}581static long582_prec(GEN p, const char *f)583{584pari_sp av = avma;585if (typ(p) == t_INT) return itos(p);586p = gceil(p);587if (typ(p) != t_INT) pari_err_TYPE(f, p);588return gc_long(av, itos(p));589}590void591localprec(GEN pp)592{593long p = _prec(pp, "localprec");594checkprec("localprec", p, prec2ndec(LGBITS));595p = ndec2nbits(p); push_localbitprec(p);596}597void598localbitprec(GEN pp)599{600long p = _prec(pp, "localbitprec");601checkprec("localbitprec", p, (long)LGBITS);602push_localbitprec(p);603}604long605getlocalprec(long prec) { return prec2ndec(prec); }606long607getlocalbitprec(long bit) { return bit; }608609static GEN610_precision0(GEN x)611{612long a = gprecision(x);613return a? utoi(prec2ndec(a)): mkoo();614}615GEN616precision0(GEN x, long n)617{ return n? gprec(x,n): _precision0(x); }618static GEN619_bitprecision0(GEN x)620{621long a = gprecision(x);622return a? utoi(prec2nbits(a)): mkoo();623}624GEN625bitprecision0(GEN x, long n)626{627if (n < 0)628pari_err_DOMAIN("bitprecision", "bitprecision", "<", gen_0, stoi(n));629if (n) {630pari_sp av = avma;631GEN y = gprec_w(x, nbits2prec(n));632return gerepilecopy(av, y);633}634return _bitprecision0(x);635}636GEN637precision00(GEN x, GEN n)638{639if (!n) return _precision0(x);640return precision0(x, _prec(n, "precision"));641}642GEN643bitprecision00(GEN x, GEN n)644{645if (!n) return _bitprecision0(x);646return bitprecision0(x, _prec(n, "bitprecision"));647}648649INLINE GEN650copyupto(GEN z, GEN t)651{652if (is_universal_constant(z) || (z>(GEN)pari_mainstack->bot && z<=t))653return z;654else655return gcopy(z);656}657658static void closure_eval(GEN C);659660INLINE GEN661get_and_reset_break(void)662{663GEN z = br_res? gcopy(br_res): gnil;664reset_break(); return z;665}666667INLINE GEN668closure_return(GEN C)669{670pari_sp av = avma;671closure_eval(C);672if (br_status) { set_avma(av); return get_and_reset_break(); }673return gerepileupto(av, gel(st,--sp));674}675676/* for the break_loop debugger. Not memory clean */677GEN678closure_evalbrk(GEN C, long *status)679{680closure_eval(C); *status = br_status;681return br_status? get_and_reset_break(): gel(st,--sp);682}683684INLINE long685closure_varn(GEN x)686{687if (!x) return -1;688if (!gequalX(x)) err_var(x);689return varn(x);690}691692INLINE void693closure_castgen(GEN z, long mode)694{695switch (mode)696{697case Ggen:698gel(st,sp++)=z;699break;700case Gsmall:701st[sp++]=gtos(z);702break;703case Gusmall:704st[sp++]=gtou(z);705break;706case Gvar:707st[sp++]=closure_varn(z);708break;709case Gvoid:710break;711default:712pari_err_BUG("closure_castgen, type unknown");713}714}715716INLINE void717closure_castlong(long z, long mode)718{719switch (mode)720{721case Gsmall:722st[sp++]=z;723break;724case Gusmall:725if (z < 0)726pari_err_TYPE("stou [integer >=0 expected]", stoi(z));727st[sp++]=(ulong) z;728break;729case Ggen:730gel(st,sp++)=stoi(z);731break;732case Gvar:733err_var(stoi(z));734case Gvoid:735break;736default:737pari_err_BUG("closure_castlong, type unknown");738}739}740741const char *742closure_func_err(void)743{744long fun=s_trace.n-1, pc;745const char *code;746GEN C, oper;747if (fun < 0 || trace[fun].pc < 0) return NULL;748pc = trace[fun].pc; C = trace[fun].closure;749code = closure_codestr(C); oper = closure_get_oper(C);750if (code[pc]==OCcallgen || code[pc]==OCcallgen2 ||751code[pc]==OCcallint || code[pc]==OCcalllong || code[pc]==OCcallvoid)752return ((entree*)oper[pc])->name;753return NULL;754}755756/* return the next label for the call chain debugger closure_err(),757* incorporating the name of the user of member function. Return NULL for an758* anonymous (inline) closure. */759static char *760get_next_label(const char *s, int member, char **next_fun)761{762const char *v, *t = s+1;763char *u, *next_label;764765if (!is_keyword_char(*s)) return NULL;766while (is_keyword_char(*t)) t++;767/* e.g. (x->1/x)(0) instead of (x)->1/x */768if (t[0] == '-' && t[1] == '>') return NULL;769next_label = (char*)pari_malloc(t - s + 32);770sprintf(next_label, "in %sfunction ", member? "member ": "");771u = *next_fun = next_label + strlen(next_label);772v = s;773while (v < t) *u++ = *v++;774*u++ = 0; return next_label;775}776777static const char *778get_arg_name(GEN C, long i)779{780GEN d = closure_get_dbg(C), frpc = gel(d,2), fram = gel(d,3);781long j, l = lg(frpc);782for (j=1; j<l; j++)783if (frpc[j]==1 && i<lg(gel(fram,j)))784return ((entree*)mael(fram,j,i))->name;785return "(unnamed)";786}787788void789closure_err(long level)790{791GEN base;792const long lastfun = s_trace.n - 1 - level;793char *next_label, *next_fun;794long i = maxss(0, lastfun - 19);795if (lastfun < 0) return; /*e.g. when called by gp_main_loop's simplify */796if (i > 0) while (lg(trace[i].closure)==6) i--;797base = closure_get_text(trace[i].closure); /* gcc -Wall*/798next_label = pari_strdup(i == 0? "at top-level": "[...] at");799next_fun = next_label;800for (; i <= lastfun; i++)801{802GEN C = trace[i].closure;803if (lg(C) >= 7) base=closure_get_text(C);804if ((i==lastfun || lg(trace[i+1].closure)>=7))805{806GEN dbg = gel(closure_get_dbg(C),1);807/* After a SIGINT, pc can be slightly off: ensure 0 <= pc < lg() */808long pc = minss(lg(dbg)-1, trace[i].pc>=0 ? trace[i].pc: 1);809long offset = pc? dbg[pc]: 0;810int member;811const char *s, *sbase;812if (typ(base)!=t_VEC) sbase = GSTR(base);813else if (offset>=0) sbase = GSTR(gel(base,2));814else { sbase = GSTR(gel(base,1)); offset += strlen(sbase); }815s = sbase + offset;816member = offset>0 && (s[-1] == '.');817/* avoid "in function foo: foo" */818if (!next_fun || strcmp(next_fun, s)) {819print_errcontext(pariErr, next_label, s, sbase);820out_putc(pariErr, '\n');821}822pari_free(next_label);823if (i == lastfun) break;824825next_label = get_next_label(s, member, &next_fun);826if (!next_label) {827next_label = pari_strdup("in anonymous function");828next_fun = NULL;829}830}831}832}833834GEN835pari_self(void)836{837long fun = s_trace.n - 1;838if (fun > 0) while (lg(trace[fun].closure)==6) fun--;839return fun >= 0 ? trace[fun].closure: NULL;840}841842long843closure_context(long start, long level)844{845const long lastfun = s_trace.n - 1 - level;846long i, fun = lastfun;847if (fun<0) return lastfun;848while (fun>start && lg(trace[fun].closure)==6) fun--;849for (i=fun; i <= lastfun; i++)850push_frame(trace[i].closure, trace[i].pc,0);851for ( ; i < s_trace.n; i++)852push_frame(trace[i].closure, trace[i].pc,1);853return s_trace.n-level;854}855856INLINE void857st_alloc(long n)858{859if (sp+n>s_st.n)860{861pari_stack_alloc(&s_st,n+16);862s_st.n=s_st.alloc;863if (DEBUGMEM>=2) pari_warn(warner,"doubling evaluator stack");864}865}866867INLINE void868ptr_proplock(gp_pointer *g, GEN C)869{870g->x = C;871if (isclone(g->x))872{873clone_unlock_deep(g->ox);874g->ox = g->x;875++bl_refc(g->ox);876}877}878879static void880closure_eval(GEN C)881{882const char *code=closure_codestr(C);883GEN oper=closure_get_oper(C);884GEN data=closure_get_data(C);885long loper=lg(oper);886long saved_sp=sp-closure_arity(C);887long saved_rp=rp, saved_prec=s_prec.n;888long j, nbmvar=0, nblvar=0, nblock=0;889long pc, t;890#ifdef STACK_CHECK891GEN stackelt;892if (PARI_stack_limit && (void*) &stackelt <= PARI_stack_limit)893pari_err(e_MISC, "deep recursion");894#endif895t = trace_push(0, C);896if (lg(C)==8)897{898GEN z=closure_get_frame(C);899long l=lg(z)-1;900pari_stack_alloc(&s_var,l);901s_var.n+=l;902nbmvar+=l;903for(j=1;j<=l;j++)904{905var[s_var.n-j].flag=PUSH_VAL;906var[s_var.n-j].value=gel(z,j);907}908}909910for(pc=1;pc<loper;pc++)911{912op_code opcode=(op_code) code[pc];913long operand=oper[pc];914if (sp<0) pari_err_BUG("closure_eval, stack underflow");915st_alloc(16);916trace[t].pc = pc;917CHECK_CTRLC918switch(opcode)919{920case OCpushlong:921st[sp++]=operand;922break;923case OCpushgnil:924gel(st,sp++)=gnil;925break;926case OCpushgen:927gel(st,sp++)=gel(data,operand);928break;929case OCpushreal:930gel(st,sp++)=strtor(GSTR(data[operand]),get_localprec());931break;932case OCpushstoi:933gel(st,sp++)=stoi(operand);934break;935case OCpushvar:936{937entree *ep = (entree *)operand;938gel(st,sp++)=pol_x(pari_var_create(ep));939break;940}941case OCpushdyn:942{943entree *ep = (entree *)operand;944if (!mt_is_thread())945{946checkvalue(ep, chk_CREATE);947gel(st,sp++)=(GEN)ep->value;948} else949{950GEN val = export_get(ep->name);951if (!val)952pari_err(e_MISC,"mt: please use export(%s)", ep->name);953gel(st,sp++)=val;954}955break;956}957case OCpushlex:958gel(st,sp++)=var[s_var.n+operand].value;959break;960case OCsimpleptrdyn:961{962gp_pointer *g = new_ptr();963g->vn=0;964g->ep = (entree*) operand;965g->x = checkvalueptr(g->ep);966g->ox = g->x; clone_lock(g->ox);967g->sp = sp;968gel(st,sp++) = (GEN)&(g->x);969break;970}971case OCsimpleptrlex:972{973gp_pointer *g = new_ptr();974g->vn=operand;975g->ep=(entree *)0x1L;976g->x = (GEN) var[s_var.n+operand].value;977g->ox = g->x; clone_lock(g->ox);978g->sp = sp;979gel(st,sp++) = (GEN)&(g->x);980break;981}982case OCnewptrdyn:983{984entree *ep = (entree *)operand;985gp_pointer *g = new_ptr();986matcomp *C;987checkvalue(ep, chk_ERROR);988g->sp = -1;989g->x = copyvalue(ep);990g->ox = g->x; clone_lock(g->ox);991g->vn=0;992g->ep=NULL;993C=&g->c;994C->full_col = C->full_row = 0;995C->parent = (GEN) g->x;996C->ptcell = (GEN *) &g->x;997break;998}999case OCnewptrlex:1000{1001gp_pointer *g = new_ptr();1002matcomp *C;1003g->sp = -1;1004g->x = copylex(operand);1005g->ox = g->x; clone_lock(g->ox);1006g->vn=0;1007g->ep=NULL;1008C=&g->c;1009C->full_col = C->full_row = 0;1010C->parent = (GEN) g->x;1011C->ptcell = (GEN *) &(g->x);1012break;1013}1014case OCpushptr:1015{1016gp_pointer *g = &ptrs[rp-1];1017g->sp = sp;1018gel(st,sp++) = (GEN)&(g->x);1019}1020break;1021case OCendptr:1022for(j=0;j<operand;j++)1023{1024gp_pointer *g = &ptrs[--rp];1025if (g->ep)1026{1027if (g->vn)1028changelex(g->vn, g->x);1029else1030changevalue(g->ep, g->x);1031}1032else change_compo(&(g->c), g->x);1033clone_unlock_deep(g->ox);1034}1035break;1036case OCstoredyn:1037{1038entree *ep = (entree *)operand;1039checkvalue(ep, chk_NOCREATE);1040changevalue(ep, gel(st,--sp));1041break;1042}1043case OCstorelex:1044changelex(operand,gel(st,--sp));1045break;1046case OCstoreptr:1047{1048gp_pointer *g = &ptrs[--rp];1049change_compo(&(g->c), gel(st,--sp));1050clone_unlock_deep(g->ox);1051break;1052}1053case OCstackgen:1054{1055GEN z = gerepileupto(st[sp-2],gel(st,sp-1));1056gmael(st,sp-3,operand) = copyupto(z,gel(st,sp-2));1057st[sp-2] = avma;1058sp--;1059break;1060}1061case OCprecreal:1062st[sp++]=get_localprec();1063break;1064case OCbitprecreal:1065st[sp++]=get_localbitprec();1066break;1067case OCprecdl:1068st[sp++]=precdl;1069break;1070case OCavma:1071st[sp++]=avma;1072break;1073case OCcowvardyn:1074{1075entree *ep = (entree *)operand;1076checkvalue(ep, chk_ERROR);1077(void)copyvalue(ep);1078break;1079}1080case OCcowvarlex:1081(void)copylex(operand);1082break;1083case OCsetref:1084setreflex(operand);1085break;1086case OClock:1087{1088GEN v = gel(st,sp-1);1089if (isclone(v))1090{1091long n = pari_stack_new(&s_locks);1092locks[n] = v;1093nblock++;1094++bl_refc(v);1095}1096break;1097}1098case OCstoi:1099gel(st,sp-1)=stoi(st[sp-1]);1100break;1101case OCutoi:1102gel(st,sp-1)=utoi(st[sp-1]);1103break;1104case OCitos:1105st[sp+operand]=gtos(gel(st,sp+operand));1106break;1107case OCitou:1108st[sp+operand]=gtou(gel(st,sp+operand));1109break;1110case OCtostr:1111{1112GEN z = gel(st,sp+operand);1113st[sp+operand] = (long) (z ? GENtostr_unquoted(z): NULL);1114break;1115}1116case OCvarn:1117st[sp+operand] = closure_varn(gel(st,sp+operand));1118break;1119case OCcopy:1120gel(st,sp-1) = gcopy(gel(st,sp-1));1121break;1122case OCgerepile:1123{1124pari_sp av;1125GEN x;1126sp--;1127av = st[sp-1];1128x = gel(st,sp);1129if (isonstack(x))1130{1131pari_sp av2 = (pari_sp)(x + lg(x));1132if ((long) (av - av2) > 1000000L)1133{1134if (DEBUGMEM>=2)1135pari_warn(warnmem,"eval: recovering %ld bytes", av - av2);1136x = gerepileupto(av, x);1137}1138} else set_avma(av);1139gel(st,sp-1) = x;1140break;1141}1142case OCcopyifclone:1143if (isclone(gel(st,sp-1)))1144gel(st,sp-1) = gcopy(gel(st,sp-1));1145break;1146case OCcompo1:1147{1148GEN p=gel(st,sp-2);1149long c=st[sp-1];1150sp-=2;1151switch(typ(p))1152{1153case t_VEC: case t_COL:1154check_array_index(c, lg(p));1155closure_castgen(gel(p,c),operand);1156break;1157case t_LIST:1158{1159long lx;1160if (list_typ(p)!=t_LIST_RAW)1161pari_err_TYPE("_[_] OCcompo1 [not a vector]", p);1162p = list_data(p); lx = p? lg(p): 1;1163check_array_index(c, lx);1164closure_castgen(gel(p,c),operand);1165break;1166}1167case t_VECSMALL:1168check_array_index(c,lg(p));1169closure_castlong(p[c],operand);1170break;1171default:1172pari_err_TYPE("_[_] OCcompo1 [not a vector]", p);1173break;1174}1175break;1176}1177case OCcompo1ptr:1178{1179long c=st[sp-1];1180long lx;1181gp_pointer *g = &ptrs[rp-1];1182matcomp *C=&g->c;1183GEN p = g->x;1184sp--;1185switch(typ(p))1186{1187case t_VEC: case t_COL:1188check_array_index(c, lg(p));1189C->ptcell = (GEN *) p+c;1190ptr_proplock(g, *(C->ptcell));1191break;1192case t_VECSMALL:1193check_array_index(c, lg(p));1194C->ptcell = (GEN *) p+c;1195g->x = stoi(p[c]);1196break;1197case t_LIST:1198if (list_typ(p)!=t_LIST_RAW)1199pari_err_TYPE("&_[_] OCcompo1 [not a vector]", p);1200p = list_data(p); lx = p? lg(p): 1;1201check_array_index(c,lx);1202C->ptcell = (GEN *) p+c;1203ptr_proplock(g, *(C->ptcell));1204break;1205default:1206pari_err_TYPE("&_[_] OCcompo1ptr [not a vector]", p);1207}1208C->parent = p;1209break;1210}1211case OCcompo2:1212{1213GEN p=gel(st,sp-3);1214long c=st[sp-2];1215long d=st[sp-1];1216if (typ(p)!=t_MAT) pari_err_TYPE("_[_,_] OCcompo2 [not a matrix]", p);1217check_array_index(d, lg(p));1218check_array_index(c, lg(gel(p,d)));1219sp-=3;1220closure_castgen(gcoeff(p,c,d),operand);1221break;1222}1223case OCcompo2ptr:1224{1225long c=st[sp-2];1226long d=st[sp-1];1227gp_pointer *g = &ptrs[rp-1];1228matcomp *C=&g->c;1229GEN p = g->x;1230sp-=2;1231if (typ(p)!=t_MAT)1232pari_err_TYPE("&_[_,_] OCcompo2ptr [not a matrix]", p);1233check_array_index(d, lg(p));1234check_array_index(c, lg(gel(p,d)));1235C->ptcell = (GEN *) gel(p,d)+c;1236C->parent = p;1237ptr_proplock(g, *(C->ptcell));1238break;1239}1240case OCcompoC:1241{1242GEN p=gel(st,sp-2);1243long c=st[sp-1];1244if (typ(p)!=t_MAT)1245pari_err_TYPE("_[,_] OCcompoC [not a matrix]", p);1246check_array_index(c, lg(p));1247sp--;1248gel(st,sp-1) = gel(p,c);1249break;1250}1251case OCcompoCptr:1252{1253long c=st[sp-1];1254gp_pointer *g = &ptrs[rp-1];1255matcomp *C=&g->c;1256GEN p = g->x;1257sp--;1258if (typ(p)!=t_MAT)1259pari_err_TYPE("&_[,_] OCcompoCptr [not a matrix]", p);1260check_array_index(c, lg(p));1261C->ptcell = (GEN *) p+c;1262C->full_col = c;1263C->parent = p;1264ptr_proplock(g, *(C->ptcell));1265break;1266}1267case OCcompoL:1268{1269GEN p=gel(st,sp-2);1270long r=st[sp-1];1271sp--;1272if (typ(p)!=t_MAT)1273pari_err_TYPE("_[_,] OCcompoL [not a matrix]", p);1274check_array_index(r,lg(p) == 1? 1: lgcols(p));1275gel(st,sp-1) = row(p,r);1276break;1277}1278case OCcompoLptr:1279{1280long r=st[sp-1];1281gp_pointer *g = &ptrs[rp-1];1282matcomp *C=&g->c;1283GEN p = g->x, p2;1284sp--;1285if (typ(p)!=t_MAT)1286pari_err_TYPE("&_[_,] OCcompoLptr [not a matrix]", p);1287check_array_index(r,lg(p) == 1? 1: lgcols(p));1288p2 = rowcopy(p,r);1289C->full_row = r; /* record row number */1290C->ptcell = &p2;1291C->parent = p;1292g->x = p2;1293break;1294}1295case OCdefaultarg:1296if (var[s_var.n+operand].flag==DEFAULT_VAL)1297{1298GEN z = gel(st,sp-1);1299if (typ(z)==t_CLOSURE)1300{1301pushlex(operand, closure_evalnobrk(z));1302copylex(operand);1303}1304else1305pushlex(operand, z);1306}1307sp--;1308break;1309case OClocalvar:1310{1311long n;1312entree *ep = (entree *)operand;1313checkvalue(ep, chk_NOCREATE);1314n = pari_stack_new(&s_lvars);1315lvars[n] = ep;1316nblvar++;1317pushvalue(ep,gel(st,--sp));1318break;1319}1320case OClocalvar0:1321{1322long n;1323entree *ep = (entree *)operand;1324checkvalue(ep, chk_NOCREATE);1325n = pari_stack_new(&s_lvars);1326lvars[n] = ep;1327nblvar++;1328zerovalue(ep);1329break;1330}1331case OCexportvar:1332{1333entree *ep = (entree *)operand;1334mt_export_add(ep->name, gel(st,--sp));1335break;1336}1337case OCunexportvar:1338{1339entree *ep = (entree *)operand;1340mt_export_del(ep->name);1341break;1342}13431344#define EVAL_f(f) \1345switch (ep->arity) \1346{ \1347case 0: f(); break; \1348case 1: sp--; f(st[sp]); break; \1349case 2: sp-=2; f(st[sp],st[sp+1]); break; \1350case 3: sp-=3; f(st[sp],st[sp+1],st[sp+2]); break; \1351case 4: sp-=4; f(st[sp],st[sp+1],st[sp+2],st[sp+3]); break; \1352case 5: sp-=5; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4]); break; \1353case 6: sp-=6; f(st[sp],st[sp+1],st[sp+2],st[sp+3],st[sp+4],st[sp+5]); break; \1354case 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; \1355case 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; \1356case 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; \1357case 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; \1358case 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; \1359case 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; \1360case 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; \1361case 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; \1362case 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; \1363case 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; \1364case 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; \1365case 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; \1366case 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; \1367case 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; \1368default: \1369pari_err_IMPL("functions with more than 20 parameters");\1370goto endeval; /*LCOV_EXCL_LINE*/ \1371}13721373case OCcallgen:1374{1375entree *ep = (entree *)operand;1376GEN res;1377/* Macro Madness : evaluate function ep->value on arguments1378* st[sp-ep->arity .. sp]. Set res = result. */1379EVAL_f(res = ((GEN (*)(ANYARG))ep->value));1380if (br_status) goto endeval;1381gel(st,sp++)=res;1382break;1383}1384case OCcallgen2: /*same for ep->arity = 2. Is this optimization worth it ?*/1385{1386entree *ep = (entree *)operand;1387GEN res;1388sp-=2;1389res = ((GEN (*)(GEN,GEN))ep->value)(gel(st,sp),gel(st,sp+1));1390if (br_status) goto endeval;1391gel(st,sp++)=res;1392break;1393}1394case OCcalllong:1395{1396entree *ep = (entree *)operand;1397long res;1398EVAL_f(res = ((long (*)(ANYARG))ep->value));1399if (br_status) goto endeval;1400st[sp++] = res;1401break;1402}1403case OCcallint:1404{1405entree *ep = (entree *)operand;1406long res;1407EVAL_f(res = ((int (*)(ANYARG))ep->value));1408if (br_status) goto endeval;1409st[sp++] = res;1410break;1411}1412case OCcallvoid:1413{1414entree *ep = (entree *)operand;1415EVAL_f(((void (*)(ANYARG))ep->value));1416if (br_status) goto endeval;1417break;1418}1419#undef EVAL_f14201421case OCcalluser:1422{1423long n=operand;1424GEN fun = gel(st,sp-1-n);1425long arity, isvar;1426GEN z;1427if (typ(fun)!=t_CLOSURE) pari_err(e_NOTFUNC, fun);1428isvar = closure_is_variadic(fun);1429arity = closure_arity(fun);1430if (!isvar || n < arity)1431{1432st_alloc(arity-n);1433if (n>arity)1434pari_err(e_MISC,"too many parameters in user-defined function call");1435for (j=n+1;j<=arity;j++)1436gel(st,sp++)=0;1437if (isvar) gel(st,sp-1) = cgetg(1,t_VEC);1438}1439else1440{1441GEN v;1442long j, m = n-arity+1;1443v = cgetg(m+1,t_VEC);1444sp-=m;1445for (j=1; j<=m; j++)1446gel(v,j) = gel(st,sp+j-1)? gcopy(gel(st,sp+j-1)): gen_0;1447gel(st,sp++)=v;1448}1449z = closure_return(fun);1450if (br_status) goto endeval;1451gel(st, sp-1) = z;1452break;1453}1454case OCnewframe:1455if (operand>0) nbmvar+=operand;1456else operand=-operand;1457pari_stack_alloc(&s_var,operand);1458s_var.n+=operand;1459for(j=1;j<=operand;j++)1460{1461var[s_var.n-j].flag=PUSH_VAL;1462var[s_var.n-j].value=gen_0;1463}1464break;1465case OCsaveframe:1466{1467GEN cl = (operand?gcopy:shallowcopy)(gel(st,sp-1));1468GEN f = gel(cl, 7);1469long j, l = lg(f);1470GEN v = cgetg(l, t_VEC);1471for (j = 1; j < l; j++)1472if (signe(gel(f,l-j))==0)1473{1474GEN val = var[s_var.n-j].value;1475gel(v,j) = operand?gcopy(val):val;1476} else1477gel(v,j) = gnil;1478gel(cl,7) = v;1479gel(st,sp-1) = cl;1480}1481break;1482case OCpackargs:1483{1484GEN def = cgetg(operand+1, t_VECSMALL);1485GEN args = cgetg(operand+1, t_VEC);1486pari_stack_alloc(&s_var,operand);1487sp-=operand;1488for (j=0;j<operand;j++)1489{1490if (gel(st,sp+j))1491{1492gel(args,j+1) = gel(st,sp+j);1493uel(def ,j+1) = 1;1494}1495else1496{1497gel(args,j+1) = gen_0;1498uel(def ,j+1) = 0;1499}1500}1501gel(st, sp++) = args;1502gel(st, sp++) = def;1503break;1504}1505case OCgetargs:1506pari_stack_alloc(&s_var,operand);1507s_var.n+=operand;1508nbmvar+=operand;1509sp-=operand;1510for (j=0;j<operand;j++)1511{1512if (gel(st,sp+j))1513pushlex(j-operand,gel(st,sp+j));1514else1515{1516var[s_var.n+j-operand].flag=DEFAULT_VAL;1517var[s_var.n+j-operand].value=gen_0;1518}1519}1520break;1521case OCcheckuserargs:1522for (j=0; j<operand; j++)1523if (var[s_var.n-operand+j].flag==DEFAULT_VAL)1524pari_err(e_MISC,"missing mandatory argument"1525" '%s' in user function",get_arg_name(C,j+1));1526break;1527case OCcheckargs:1528for (j=sp-1;operand;operand>>=1UL,j--)1529if ((operand&1L) && gel(st,j)==NULL)1530pari_err(e_MISC,"missing mandatory argument");1531break;1532case OCcheckargs0:1533for (j=sp-1;operand;operand>>=1UL,j--)1534if ((operand&1L) && gel(st,j))1535pari_err(e_MISC,"argument type not implemented");1536break;1537case OCdefaultlong:1538sp--;1539if (st[sp+operand])1540st[sp+operand]=gtos(gel(st,sp+operand));1541else1542st[sp+operand]=st[sp];1543break;1544case OCdefaultulong:1545sp--;1546if (st[sp+operand])1547st[sp+operand]=gtou(gel(st,sp+operand));1548else1549st[sp+operand]=st[sp];1550break;1551case OCdefaultgen:1552sp--;1553if (!st[sp+operand])1554st[sp+operand]=st[sp];1555break;1556case OCvec:1557gel(st,sp++)=cgetg(operand,t_VEC);1558st[sp++]=avma;1559break;1560case OCcol:1561gel(st,sp++)=cgetg(operand,t_COL);1562st[sp++]=avma;1563break;1564case OCmat:1565{1566GEN z;1567long l=st[sp-1];1568z=cgetg(operand,t_MAT);1569for(j=1;j<operand;j++)1570gel(z,j) = cgetg(l,t_COL);1571gel(st,sp-1) = z;1572st[sp++]=avma;1573}1574break;1575case OCpop:1576sp-=operand;1577break;1578case OCdup:1579{1580long i, s=st[sp-1];1581st_alloc(operand);1582for(i=1;i<=operand;i++)1583st[sp++]=s;1584}1585break;1586}1587}1588if (0)1589{1590endeval:1591sp = saved_sp;1592for( ; rp>saved_rp ; )1593{1594gp_pointer *g = &ptrs[--rp];1595clone_unlock_deep(g->ox);1596}1597}1598s_prec.n = saved_prec;1599s_trace.n--;1600restore_vars(nbmvar, nblvar, nblock);1601clone_unlock(C);1602}16031604GEN1605closure_evalgen(GEN C)1606{1607pari_sp ltop=avma;1608closure_eval(C);1609if (br_status) return gc_NULL(ltop);1610return gerepileupto(ltop,gel(st,--sp));1611}16121613long1614evalstate_get_trace(void)1615{ return s_trace.n; }16161617void1618evalstate_set_trace(long lvl)1619{ s_trace.n = lvl; }16201621void1622evalstate_save(struct pari_evalstate *state)1623{1624state->avma = avma;1625state->sp = sp;1626state->rp = rp;1627state->prec = s_prec.n;1628state->var = s_var.n;1629state->lvars= s_lvars.n;1630state->locks= s_locks.n;1631state->trace= s_trace.n;1632compilestate_save(&state->comp);1633mtstate_save(&state->mt);1634}16351636void1637evalstate_restore(struct pari_evalstate *state)1638{1639set_avma(state->avma);1640mtstate_restore(&state->mt);1641sp = state->sp;1642rp = state->rp;1643s_prec.n = state->prec;1644restore_vars(s_var.n-state->var, s_lvars.n-state->lvars,1645s_locks.n-state->locks);1646restore_trace(s_trace.n-state->trace);1647reset_break();1648compilestate_restore(&state->comp);1649}16501651GEN1652evalstate_restore_err(struct pari_evalstate *state)1653{1654GENbin* err = copy_bin(pari_err_last());1655evalstate_restore(state);1656return bin_copy(err);1657}16581659void1660evalstate_reset(void)1661{1662mtstate_reset();1663restore_vars(s_var.n, s_lvars.n, s_locks.n);1664sp = rp = dbg_level = s_trace.n = 0;1665reset_break();1666compilestate_reset();1667parsestate_reset();1668set_avma(pari_mainstack->top);1669}16701671void1672evalstate_clone(void)1673{1674long i;1675for (i = 1; i<=s_var.n; i++) copylex(-i);1676lvar_make_safe();1677for (i = 0; i< s_trace.n; i++)1678{1679GEN C = trace[i].closure;1680if (isonstack(C)) trace[i].closure = gclone(C);1681}1682}16831684GEN1685closure_trapgen(GEN C, long numerr)1686{1687VOLATILE GEN x;1688struct pari_evalstate state;1689evalstate_save(&state);1690pari_CATCH(numerr) { x = (GEN)1L; }1691pari_TRY { x = closure_evalgen(C); } pari_ENDCATCH;1692if (x == (GEN)1L) evalstate_restore(&state);1693return x;1694}16951696GEN1697closure_evalnobrk(GEN C)1698{1699pari_sp ltop=avma;1700closure_eval(C);1701if (br_status) pari_err(e_MISC, "break not allowed here");1702return gerepileupto(ltop,gel(st,--sp));1703}17041705void1706closure_evalvoid(GEN C)1707{1708pari_sp ltop=avma;1709closure_eval(C);1710set_avma(ltop);1711}17121713GEN1714closure_evalres(GEN C)1715{1716return closure_return(C);1717}17181719INLINE GEN1720closure_returnupto(GEN C)1721{1722pari_sp av=avma;1723return copyupto(closure_return(C),(GEN)av);1724}17251726GEN1727pareval_worker(GEN C)1728{1729return closure_callgenall(C, 0);1730}17311732GEN1733pareval(GEN C)1734{1735pari_sp av = avma;1736long l = lg(C), i;1737GEN worker;1738if (!is_vec_t(typ(C))) pari_err_TYPE("pareval",C);1739for (i=1; i<l; i++)1740if (typ(gel(C,i))!=t_CLOSURE)1741pari_err_TYPE("pareval",gel(C,i));1742worker = snm_closure(is_entry("_pareval_worker"), NULL);1743return gerepileupto(av, gen_parapply(worker, C));1744}17451746GEN1747parvector_worker(GEN i, GEN C)1748{1749return closure_callgen1(C, i);1750}17511752GEN1753parfor_worker(GEN i, GEN C)1754{1755retmkvec2(gcopy(i), closure_callgen1(C, i));1756}17571758GEN1759parvector(long n, GEN code)1760{1761long i, pending = 0, workid;1762GEN worker = snm_closure(is_entry("_parvector_worker"), mkvec(code));1763GEN a, V, done;1764struct pari_mt pt;1765mt_queue_start_lim(&pt, worker, n);1766a = mkvec(cgetipos(3)); /* left on the stack */1767V = cgetg(n+1, t_VEC);1768for (i=1; i<=n || pending; i++)1769{1770mael(a,1,2) = i;1771mt_queue_submit(&pt, i, i<=n? a: NULL);1772done = mt_queue_get(&pt, &workid, &pending);1773if (done) gel(V,workid) = done;1774}1775mt_queue_end(&pt);1776return V;1777}17781779/* B <- {a + k * m : k = 0, ..., (b-a)/m)} */1780static void1781arithprogset(GEN B, GEN a, GEN b, long m)1782{1783long k;1784for (k = 1; cmpii(a, b) <= 0; a = addui(m,a), k++) gel(B, k) = a;1785setlg(B, k);1786}1787static GEN1788vecsum_i(GEN v)1789{1790long i, l = lg(v);1791GEN s;1792if (l == 1) return gen_0;1793s = gel(v,1); for (i = 2; i < l; i++) s = gadd(s, gel(v,i));1794return s;1795}1796GEN1797parsum(GEN a, GEN b, GEN code)1798{1799pari_sp av = avma;1800GEN worker, L, v, s, N;1801long r, m, pending;1802struct pari_mt pt;1803pari_sp av2;18041805if (typ(a) != t_INT) pari_err_TYPE("parsum",a);1806if (gcmp(b,a) < 0) return gen_0;1807worker = snm_closure(is_entry("_parapply_slice_worker"), mkvec(code));1808b = gfloor(b);1809N = addiu(subii(b, a), 1);1810m = itou(sqrti(N));1811mt_queue_start_lim(&pt, worker, m);1812L = cgetg(m + 2, t_VEC); v = mkvec(L);1813s = gen_0; a = setloop(a); pending = 0; av2 = avma;1814for (r = 1; r <= m || pending; r++)1815{1816long workid;1817GEN done;1818if (r <= m) { arithprogset(L, icopy(a), b, m); a = incloop(a); }1819mt_queue_submit(&pt, 0, r <= m? v: NULL);1820done = mt_queue_get(&pt, &workid, &pending);1821if (done) s = gerepileupto(av2, gadd(s, vecsum_i(done)));1822}1823mt_queue_end(&pt); return gerepileupto(av, s);1824}18251826void1827parfor(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN))1828{1829pari_sp av = avma, av2;1830long running, pending = 0, lim;1831long status = br_NONE;1832GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));1833GEN done, stop = NULL;1834struct pari_mt pt;1835if (typ(a) != t_INT) pari_err_TYPE("parfor",a);1836if (b)1837{1838if (gcmp(b,a) < 0) return;1839if (typ(b) == t_INFINITY)1840{1841if (inf_get_sign(b) < 0) return;1842b = NULL;1843}1844else1845b = gfloor(b);1846}1847lim = b ? itos_or_0(subii(addis(b,1),a)): 0;1848mt_queue_start_lim(&pt, worker, lim);1849a = mkvec(setloop(a));1850av2 = avma;1851while ((running = (!stop && (!b || cmpii(gel(a,1),b) <= 0))) || pending)1852{1853mt_queue_submit(&pt, 0, running ? a: NULL);1854done = mt_queue_get(&pt, NULL, &pending);1855if (call && done && (!stop || cmpii(gel(done,1),stop) < 0))1856if (call(E, gel(done,1), gel(done,2)))1857{1858status = br_status;1859br_status = br_NONE;1860stop = gerepileuptoint(av2, gel(done,1));1861}1862gel(a,1) = incloop(gel(a,1));1863if (!stop) set_avma(av2);1864}1865set_avma(av2);1866mt_queue_end(&pt);1867br_status = status;1868set_avma(av);1869}18701871static void1872parforiter_init(struct parfor_iter *T, GEN code)1873{1874T->pending = 0;1875T->worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));1876mt_queue_start(&T->pt, T->worker);1877}18781879static GEN1880parforiter_next(struct parfor_iter *T, GEN v)1881{1882mt_queue_submit(&T->pt, 0, v);1883return mt_queue_get(&T->pt, NULL, &T->pending);1884}18851886static void1887parforiter_stop(struct parfor_iter *T)1888{1889while (T->pending)1890{1891mt_queue_submit(&T->pt, 0, NULL);1892(void) mt_queue_get(&T->pt, NULL, &T->pending);1893}1894mt_queue_end(&T->pt);1895}18961897void1898parfor_init(parfor_t *T, GEN a, GEN b, GEN code)1899{1900if (typ(a) != t_INT) pari_err_TYPE("parfor",a);1901T->b = b ? gfloor(b): NULL;1902T->a = mkvec(setloop(a));1903parforiter_init(&T->iter, code);1904}19051906GEN1907parfor_next(parfor_t *T)1908{1909long running;1910while ((running=((!T->b || cmpii(gel(T->a,1),T->b) <= 0))) || T->iter.pending)1911{1912GEN done = parforiter_next(&T->iter, running ? T->a: NULL);1913gel(T->a,1) = incloop(gel(T->a,1));1914if (done) return done;1915}1916mt_queue_end(&T->iter.pt);1917return NULL;1918}19191920void1921parfor_stop(parfor_t *T) { parforiter_stop(&T->iter); }19221923static long1924gp_evalvoid2(void *E, GEN x, GEN y)1925{1926GEN code =(GEN) E;1927push_lex(x, code);1928push_lex(y, NULL);1929closure_evalvoid(code);1930pop_lex(2);1931return loop_break();1932}19331934void1935parfor0(GEN a, GEN b, GEN code, GEN code2)1936{1937parfor(a, b, code, (void*)code2, code2 ? gp_evalvoid2: NULL);1938}19391940void1941parforprimestep_init(parforprime_t *T, GEN a, GEN b, GEN q, GEN code)1942{1943forprimestep_init(&T->forprime, a, b, q);1944T->v = mkvec(gen_0);1945parforiter_init(&T->iter, code);1946}19471948void1949parforprime_init(parforprime_t *T, GEN a, GEN b, GEN code)1950{ parforprimestep_init(T, a, b, NULL, code); }19511952GEN1953parforprime_next(parforprime_t *T)1954{1955long running;1956while ((running = !!forprime_next(&T->forprime)) || T->iter.pending)1957{1958GEN done;1959gel(T->v, 1) = T->forprime.pp;1960done = parforiter_next(&T->iter, running ? T->v: NULL);1961if (done) return done;1962}1963mt_queue_end(&T->iter.pt);1964return NULL;1965}19661967void1968parforprime_stop(parforprime_t *T) { parforiter_stop(&T->iter); }19691970void1971parforprimestep(GEN a, GEN b, GEN q, GEN code, void *E, long call(void*, GEN, GEN))1972{1973pari_sp av = avma, av2;1974long running, pending = 0;1975long status = br_NONE;1976GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));1977GEN v, done, stop = NULL;1978struct pari_mt pt;1979forprime_t T;19801981if (!forprimestep_init(&T, a,b,q)) { set_avma(av); return; }1982mt_queue_start(&pt, worker);1983v = mkvec(gen_0);1984av2 = avma;1985while ((running = (!stop && forprime_next(&T))) || pending)1986{1987gel(v, 1) = T.pp;1988mt_queue_submit(&pt, 0, running ? v: NULL);1989done = mt_queue_get(&pt, NULL, &pending);1990if (call && done && (!stop || cmpii(gel(done,1),stop) < 0))1991if (call(E, gel(done,1), gel(done,2)))1992{1993status = br_status;1994br_status = br_NONE;1995stop = gerepileuptoint(av2, gel(done,1));1996}1997if (!stop) set_avma(av2);1998}1999set_avma(av2);2000mt_queue_end(&pt);2001br_status = status;2002set_avma(av);2003}20042005void2006parforprime(GEN a, GEN b, GEN code, void *E, long call(void*, GEN, GEN))2007{2008parforprimestep(a, b, NULL, code, E, call);2009}20102011void2012parforprime0(GEN a, GEN b, GEN code, GEN code2)2013{2014parforprime(a, b, code, (void*)code2, code2? gp_evalvoid2: NULL);2015}20162017void2018parforprimestep0(GEN a, GEN b, GEN q, GEN code, GEN code2)2019{2020parforprimestep(a, b, q, code, (void*)code2, code2? gp_evalvoid2: NULL);2021}20222023void2024parforvec_init(parforvec_t *T, GEN x, GEN code, long flag)2025{2026forvec_init(&T->forvec, x, flag);2027T->v = mkvec(gen_0);2028parforiter_init(&T->iter, code);2029}20302031GEN2032parforvec_next(parforvec_t *T)2033{2034GEN v = gen_0;2035while ((v = forvec_next(&T->forvec)) || T->iter.pending)2036{2037GEN done;2038if (v) gel(T->v, 1) = v;2039done = parforiter_next(&T->iter, v ? T->v: NULL);2040if (done) return done;2041}2042mt_queue_end(&T->iter.pt);2043return NULL;2044}20452046void2047parforvec_stop(parforvec_t *T) { parforiter_stop(&T->iter); }20482049void2050parforvec(GEN x, GEN code, long flag, void *E, long call(void*, GEN, GEN))2051{2052pari_sp av = avma, av2;2053long running, pending = 0;2054long status = br_NONE;2055GEN worker = snm_closure(is_entry("_parfor_worker"), mkvec(code));2056GEN done, stop = NULL;2057struct pari_mt pt;2058forvec_t T;2059GEN a, v = gen_0;20602061if (!forvec_init(&T, x, flag)) { set_avma(av); return; }2062mt_queue_start(&pt, worker);2063a = mkvec(gen_0);2064av2 = avma;2065while ((running = (!stop && v && (v = forvec_next(&T)))) || pending)2066{2067gel(a, 1) = v;2068mt_queue_submit(&pt, 0, running ? a: NULL);2069done = mt_queue_get(&pt, NULL, &pending);2070if (call && done && (!stop || lexcmp(gel(done,1),stop) < 0))2071if (call(E, gel(done,1), gel(done,2)))2072{2073status = br_status;2074br_status = br_NONE;2075stop = gerepilecopy(av2, gel(done,1));2076}2077if (!stop) set_avma(av2);2078}2079set_avma(av2);2080mt_queue_end(&pt);2081br_status = status;2082set_avma(av);2083}20842085void2086parforvec0(GEN x, GEN code, GEN code2, long flag)2087{2088parforvec(x, code, flag, (void*)code2, code2? gp_evalvoid2: NULL);2089}20902091void2092parforeach_init(parforeach_t *T, GEN x, GEN code)2093{2094switch(typ(x))2095{2096case t_LIST:2097x = list_data(x); /* FALL THROUGH */2098if (!x) return;2099case t_MAT: case t_VEC: case t_COL:2100break;2101default:2102pari_err_TYPE("foreach",x);2103return; /*LCOV_EXCL_LINE*/2104}2105T->x = x; T->i = 1; T->l = lg(x);2106T->W = mkvec(gen_0);2107T->iter.pending = 0;2108T->iter.worker = snm_closure(is_entry("_parvector_worker"), mkvec(code));2109mt_queue_start(&T->iter.pt, T->iter.worker);2110}21112112GEN2113parforeach_next(parforeach_t *T)2114{2115while (T->i < T->l || T->iter.pending)2116{2117GEN done;2118long workid;2119if (T->i < T->l) gel(T->W,1) = gel(T->x, T->i);2120mt_queue_submit(&T->iter.pt, T->i, T->i < T->l ? T->W: NULL);2121T->i = minss(T->i+1, T->l);2122done = mt_queue_get(&T->iter.pt, &workid, &T->iter.pending);2123if (done) return mkvec2(gel(T->x,workid),done);2124}2125mt_queue_end(&T->iter.pt);2126return NULL;2127}21282129void2130parforeach_stop(parforeach_t *T) { parforiter_stop(&T->iter); }21312132void2133parforeach(GEN x, GEN code, void *E, long call(void*, GEN, GEN))2134{2135pari_sp av = avma, av2;2136long pending = 0, n, i, stop = 0;2137long status = br_NONE, workid;2138GEN worker = snm_closure(is_entry("_parvector_worker"), mkvec(code));2139GEN done, W;2140struct pari_mt pt;2141switch(typ(x))2142{2143case t_LIST:2144x = list_data(x); /* FALL THROUGH */2145if (!x) return;2146case t_MAT: case t_VEC: case t_COL:2147break;2148default:2149pari_err_TYPE("foreach",x);2150return; /*LCOV_EXCL_LINE*/2151}2152clone_lock(x); n = lg(x)-1;2153mt_queue_start_lim(&pt, worker, n);2154W = cgetg(2, t_VEC);2155av2 = avma;2156for (i=1; i<=n || pending; i++)2157{2158if (!stop && i <= n) gel(W,1) = gel(x,i);2159mt_queue_submit(&pt, i, !stop && i<=n? W: NULL);2160done = mt_queue_get(&pt, &workid, &pending);2161if (call && done && (!stop || workid < stop))2162if (call(E, gel(x, workid), done))2163{2164status = br_status;2165br_status = br_NONE;2166stop = workid;2167}2168}2169set_avma(av2);2170mt_queue_end(&pt);2171br_status = status;2172set_avma(av);2173}21742175void2176parforeach0(GEN x, GEN code, GEN code2)2177{2178parforeach(x, code, (void*)code2, code2? gp_evalvoid2: NULL);2179}21802181void2182closure_callvoid1(GEN C, GEN x)2183{2184long i, ar = closure_arity(C);2185gel(st,sp++) = x;2186for(i=2; i <= ar; i++) gel(st,sp++) = NULL;2187closure_evalvoid(C);2188}21892190GEN2191closure_callgen0prec(GEN C, long prec)2192{2193GEN z;2194long i, ar = closure_arity(C);2195for(i=1; i<= ar; i++) gel(st,sp++) = NULL;2196push_localprec(prec);2197z = closure_returnupto(C);2198pop_localprec();2199return z;2200}22012202GEN2203closure_callgen1(GEN C, GEN x)2204{2205long i, ar = closure_arity(C);2206gel(st,sp++) = x;2207for(i=2; i<= ar; i++) gel(st,sp++) = NULL;2208return closure_returnupto(C);2209}22102211GEN2212closure_callgen1prec(GEN C, GEN x, long prec)2213{2214GEN z;2215long i, ar = closure_arity(C);2216gel(st,sp++) = x;2217for(i=2; i<= ar; i++) gel(st,sp++) = NULL;2218push_localprec(prec);2219z = closure_returnupto(C);2220pop_localprec();2221return z;2222}22232224GEN2225closure_callgen2(GEN C, GEN x, GEN y)2226{2227long i, ar = closure_arity(C);2228st_alloc(ar);2229gel(st,sp++) = x;2230gel(st,sp++) = y;2231for(i=3; i<=ar; i++) gel(st,sp++) = NULL;2232return closure_returnupto(C);2233}22342235GEN2236closure_callgenvec(GEN C, GEN args)2237{2238long i, l = lg(args)-1, ar = closure_arity(C);2239st_alloc(ar);2240if (l > ar)2241pari_err(e_MISC,"too many parameters in user-defined function call");2242if (closure_is_variadic(C) && l==ar && typ(gel(args,l))!=t_VEC)2243pari_err_TYPE("call", gel(args,l));2244for (i = 1; i <= l; i++) gel(st,sp++) = gel(args,i);2245for( ; i <= ar; i++) gel(st,sp++) = NULL;2246return closure_returnupto(C);2247}22482249GEN2250closure_callgenvecprec(GEN C, GEN args, long prec)2251{2252GEN z;2253push_localprec(prec);2254z = closure_callgenvec(C, args);2255pop_localprec();2256return z;2257}22582259GEN2260closure_callgenvecdef(GEN C, GEN args, GEN def)2261{2262long i, l = lg(args)-1, ar = closure_arity(C);2263st_alloc(ar);2264if (l > ar)2265pari_err(e_MISC,"too many parameters in user-defined function call");2266if (closure_is_variadic(C) && l==ar && typ(gel(args,l))!=t_VEC)2267pari_err_TYPE("call", gel(args,l));2268for (i = 1; i <= l; i++) gel(st,sp++) = def[i] ? gel(args,i): NULL;2269for( ; i <= ar; i++) gel(st,sp++) = NULL;2270return closure_returnupto(C);2271}22722273GEN2274closure_callgenvecdefprec(GEN C, GEN args, GEN def, long prec)2275{2276GEN z;2277push_localprec(prec);2278z = closure_callgenvecdef(C, args, def);2279pop_localprec();2280return z;2281}2282GEN2283closure_callgenall(GEN C, long n, ...)2284{2285va_list ap;2286long i, ar = closure_arity(C);2287va_start(ap,n);2288if (n > ar)2289pari_err(e_MISC,"too many parameters in user-defined function call");2290st_alloc(ar);2291for (i = 1; i <=n; i++) gel(st,sp++) = va_arg(ap, GEN);2292for( ; i <=ar; i++) gel(st,sp++) = NULL;2293va_end(ap);2294return closure_returnupto(C);2295}22962297GEN2298gp_eval(void *E, GEN x)2299{2300GEN code = (GEN)E;2301set_lex(-1,x);2302return closure_evalnobrk(code);2303}23042305GEN2306gp_evalupto(void *E, GEN x)2307{2308pari_sp av = avma;2309return copyupto(gp_eval(E,x), (GEN)av);2310}23112312GEN2313gp_evalprec(void *E, GEN x, long prec)2314{2315GEN z;2316push_localprec(prec);2317z = gp_eval(E, x);2318pop_localprec();2319return z;2320}23212322long2323gp_evalbool(void *E, GEN x)2324{ pari_sp av = avma; return gc_long(av, !gequal0(gp_eval(E,x))); }23252326long2327gp_evalvoid(void *E, GEN x)2328{2329GEN code = (GEN)E;2330set_lex(-1,x);2331closure_evalvoid(code);2332return loop_break();2333}23342335GEN2336gp_call(void *E, GEN x)2337{2338GEN code = (GEN)E;2339return closure_callgen1(code, x);2340}23412342GEN2343gp_callprec(void *E, GEN x, long prec)2344{2345GEN code = (GEN)E;2346return closure_callgen1prec(code, x, prec);2347}23482349GEN2350gp_call2(void *E, GEN x, GEN y)2351{2352GEN code = (GEN)E;2353return closure_callgen2(code, x, y);2354}23552356long2357gp_callbool(void *E, GEN x)2358{2359pari_sp av = avma;2360GEN code = (GEN)E;2361return gc_long(av, !gequal0(closure_callgen1(code, x)));2362}23632364long2365gp_callvoid(void *E, GEN x)2366{2367GEN code = (GEN)E;2368closure_callvoid1(code, x);2369return loop_break();2370}23712372INLINE const char *2373disassemble_cast(long mode)2374{2375switch (mode)2376{2377case Gsmall:2378return "small";2379case Ggen:2380return "gen";2381case Gvar:2382return "var";2383case Gvoid:2384return "void";2385default:2386return "unknown";2387}2388}23892390void2391closure_disassemble(GEN C)2392{2393const char * code;2394GEN oper;2395long i;2396if (typ(C)!=t_CLOSURE) pari_err_TYPE("disassemble",C);2397code=closure_codestr(C);2398oper=closure_get_oper(C);2399for(i=1;i<lg(oper);i++)2400{2401op_code opcode=(op_code) code[i];2402long operand=oper[i];2403pari_printf("%05ld\t",i);2404switch(opcode)2405{2406case OCpushlong:2407pari_printf("pushlong\t%ld\n",operand);2408break;2409case OCpushgnil:2410pari_printf("pushgnil\n");2411break;2412case OCpushgen:2413pari_printf("pushgen\t\t%ld\n",operand);2414break;2415case OCpushreal:2416pari_printf("pushreal\t%ld\n",operand);2417break;2418case OCpushstoi:2419pari_printf("pushstoi\t%ld\n",operand);2420break;2421case OCpushvar:2422{2423entree *ep = (entree *)operand;2424pari_printf("pushvar\t%s\n",ep->name);2425break;2426}2427case OCpushdyn:2428{2429entree *ep = (entree *)operand;2430pari_printf("pushdyn\t\t%s\n",ep->name);2431break;2432}2433case OCpushlex:2434pari_printf("pushlex\t\t%ld\n",operand);2435break;2436case OCstoredyn:2437{2438entree *ep = (entree *)operand;2439pari_printf("storedyn\t%s\n",ep->name);2440break;2441}2442case OCstorelex:2443pari_printf("storelex\t%ld\n",operand);2444break;2445case OCstoreptr:2446pari_printf("storeptr\n");2447break;2448case OCsimpleptrdyn:2449{2450entree *ep = (entree *)operand;2451pari_printf("simpleptrdyn\t%s\n",ep->name);2452break;2453}2454case OCsimpleptrlex:2455pari_printf("simpleptrlex\t%ld\n",operand);2456break;2457case OCnewptrdyn:2458{2459entree *ep = (entree *)operand;2460pari_printf("newptrdyn\t%s\n",ep->name);2461break;2462}2463case OCnewptrlex:2464pari_printf("newptrlex\t%ld\n",operand);2465break;2466case OCpushptr:2467pari_printf("pushptr\n");2468break;2469case OCstackgen:2470pari_printf("stackgen\t%ld\n",operand);2471break;2472case OCendptr:2473pari_printf("endptr\t\t%ld\n",operand);2474break;2475case OCprecreal:2476pari_printf("precreal\n");2477break;2478case OCbitprecreal:2479pari_printf("bitprecreal\n");2480break;2481case OCprecdl:2482pari_printf("precdl\n");2483break;2484case OCstoi:2485pari_printf("stoi\n");2486break;2487case OCutoi:2488pari_printf("utoi\n");2489break;2490case OCitos:2491pari_printf("itos\t\t%ld\n",operand);2492break;2493case OCitou:2494pari_printf("itou\t\t%ld\n",operand);2495break;2496case OCtostr:2497pari_printf("tostr\t\t%ld\n",operand);2498break;2499case OCvarn:2500pari_printf("varn\t\t%ld\n",operand);2501break;2502case OCcopy:2503pari_printf("copy\n");2504break;2505case OCcopyifclone:2506pari_printf("copyifclone\n");2507break;2508case OCcompo1:2509pari_printf("compo1\t\t%s\n",disassemble_cast(operand));2510break;2511case OCcompo1ptr:2512pari_printf("compo1ptr\n");2513break;2514case OCcompo2:2515pari_printf("compo2\t\t%s\n",disassemble_cast(operand));2516break;2517case OCcompo2ptr:2518pari_printf("compo2ptr\n");2519break;2520case OCcompoC:2521pari_printf("compoC\n");2522break;2523case OCcompoCptr:2524pari_printf("compoCptr\n");2525break;2526case OCcompoL:2527pari_printf("compoL\n");2528break;2529case OCcompoLptr:2530pari_printf("compoLptr\n");2531break;2532case OCcheckargs:2533pari_printf("checkargs\t0x%lx\n",operand);2534break;2535case OCcheckargs0:2536pari_printf("checkargs0\t0x%lx\n",operand);2537break;2538case OCcheckuserargs:2539pari_printf("checkuserargs\t%ld\n",operand);2540break;2541case OCdefaultlong:2542pari_printf("defaultlong\t%ld\n",operand);2543break;2544case OCdefaultulong:2545pari_printf("defaultulong\t%ld\n",operand);2546break;2547case OCdefaultgen:2548pari_printf("defaultgen\t%ld\n",operand);2549break;2550case OCpackargs:2551pari_printf("packargs\t%ld\n",operand);2552break;2553case OCgetargs:2554pari_printf("getargs\t\t%ld\n",operand);2555break;2556case OCdefaultarg:2557pari_printf("defaultarg\t%ld\n",operand);2558break;2559case OClocalvar:2560{2561entree *ep = (entree *)operand;2562pari_printf("localvar\t%s\n",ep->name);2563break;2564}2565case OClocalvar0:2566{2567entree *ep = (entree *)operand;2568pari_printf("localvar0\t%s\n",ep->name);2569break;2570}2571case OCexportvar:2572{2573entree *ep = (entree *)operand;2574pari_printf("exportvar\t%s\n",ep->name);2575break;2576}2577case OCunexportvar:2578{2579entree *ep = (entree *)operand;2580pari_printf("unexportvar\t%s\n",ep->name);2581break;2582}2583case OCcallgen:2584{2585entree *ep = (entree *)operand;2586pari_printf("callgen\t\t%s\n",ep->name);2587break;2588}2589case OCcallgen2:2590{2591entree *ep = (entree *)operand;2592pari_printf("callgen2\t%s\n",ep->name);2593break;2594}2595case OCcalllong:2596{2597entree *ep = (entree *)operand;2598pari_printf("calllong\t%s\n",ep->name);2599break;2600}2601case OCcallint:2602{2603entree *ep = (entree *)operand;2604pari_printf("callint\t\t%s\n",ep->name);2605break;2606}2607case OCcallvoid:2608{2609entree *ep = (entree *)operand;2610pari_printf("callvoid\t%s\n",ep->name);2611break;2612}2613case OCcalluser:2614pari_printf("calluser\t%ld\n",operand);2615break;2616case OCvec:2617pari_printf("vec\t\t%ld\n",operand);2618break;2619case OCcol:2620pari_printf("col\t\t%ld\n",operand);2621break;2622case OCmat:2623pari_printf("mat\t\t%ld\n",operand);2624break;2625case OCnewframe:2626pari_printf("newframe\t%ld\n",operand);2627break;2628case OCsaveframe:2629pari_printf("saveframe\t%ld\n", operand);2630break;2631case OCpop:2632pari_printf("pop\t\t%ld\n",operand);2633break;2634case OCdup:2635pari_printf("dup\t\t%ld\n",operand);2636break;2637case OCavma:2638pari_printf("avma\n",operand);2639break;2640case OCgerepile:2641pari_printf("gerepile\n",operand);2642break;2643case OCcowvardyn:2644{2645entree *ep = (entree *)operand;2646pari_printf("cowvardyn\t%s\n",ep->name);2647break;2648}2649case OCcowvarlex:2650pari_printf("cowvarlex\t%ld\n",operand);2651break;2652case OCsetref:2653pari_printf("setref\t\t%ld\n",operand);2654break;2655case OClock:2656pari_printf("lock\t\t%ld\n",operand);2657break;2658}2659}2660}26612662static int2663opcode_need_relink(op_code opcode)2664{2665switch(opcode)2666{2667case OCpushlong:2668case OCpushgen:2669case OCpushgnil:2670case OCpushreal:2671case OCpushstoi:2672case OCpushlex:2673case OCstorelex:2674case OCstoreptr:2675case OCsimpleptrlex:2676case OCnewptrlex:2677case OCpushptr:2678case OCstackgen:2679case OCendptr:2680case OCprecreal:2681case OCbitprecreal:2682case OCprecdl:2683case OCstoi:2684case OCutoi:2685case OCitos:2686case OCitou:2687case OCtostr:2688case OCvarn:2689case OCcopy:2690case OCcopyifclone:2691case OCcompo1:2692case OCcompo1ptr:2693case OCcompo2:2694case OCcompo2ptr:2695case OCcompoC:2696case OCcompoCptr:2697case OCcompoL:2698case OCcompoLptr:2699case OCcheckargs:2700case OCcheckargs0:2701case OCcheckuserargs:2702case OCpackargs:2703case OCgetargs:2704case OCdefaultarg:2705case OCdefaultgen:2706case OCdefaultlong:2707case OCdefaultulong:2708case OCcalluser:2709case OCvec:2710case OCcol:2711case OCmat:2712case OCnewframe:2713case OCsaveframe:2714case OCdup:2715case OCpop:2716case OCavma:2717case OCgerepile:2718case OCcowvarlex:2719case OCsetref:2720case OClock:2721break;2722case OCpushvar:2723case OCpushdyn:2724case OCstoredyn:2725case OCsimpleptrdyn:2726case OCnewptrdyn:2727case OClocalvar:2728case OClocalvar0:2729case OCexportvar:2730case OCunexportvar:2731case OCcallgen:2732case OCcallgen2:2733case OCcalllong:2734case OCcallint:2735case OCcallvoid:2736case OCcowvardyn:2737return 1;2738}2739return 0;2740}27412742static void2743closure_relink(GEN C, hashtable *table)2744{2745const char *code = closure_codestr(C);2746GEN oper = closure_get_oper(C);2747GEN fram = gel(closure_get_dbg(C),3);2748long i, j;2749for(i=1;i<lg(oper);i++)2750if (oper[i] && opcode_need_relink((op_code)code[i]))2751oper[i] = (long) hash_search(table,(void*) oper[i])->val;2752for (i=1;i<lg(fram);i++)2753for (j=1;j<lg(gel(fram,i));j++)2754if (mael(fram,i,j))2755mael(fram,i,j) = (long) hash_search(table,(void*) mael(fram,i,j))->val;2756}27572758void2759gen_relink(GEN x, hashtable *table)2760{2761long i, lx, tx = typ(x);2762switch(tx)2763{2764case t_CLOSURE:2765closure_relink(x, table);2766gen_relink(closure_get_data(x), table);2767if (lg(x)==8) gen_relink(closure_get_frame(x), table);2768break;2769case t_LIST:2770if (list_data(x)) gen_relink(list_data(x), table);2771break;2772case t_VEC: case t_COL: case t_MAT: case t_ERROR:2773lx = lg(x);2774for (i=lontyp[tx]; i<lx; i++) gen_relink(gel(x,i), table);2775}2776}27772778static void2779closure_unlink(GEN C)2780{2781const char *code = closure_codestr(C);2782GEN oper = closure_get_oper(C);2783GEN fram = gel(closure_get_dbg(C),3);2784long i, j;2785for(i=1;i<lg(oper);i++)2786if (oper[i] && opcode_need_relink((op_code) code[i]))2787{2788long n = pari_stack_new(&s_relocs);2789relocs[n] = (entree *) oper[i];2790}2791for (i=1;i<lg(fram);i++)2792for (j=1;j<lg(gel(fram,i));j++)2793if (mael(fram,i,j))2794{2795long n = pari_stack_new(&s_relocs);2796relocs[n] = (entree *) mael(fram,i,j);2797}2798}27992800static void2801gen_unlink(GEN x)2802{2803long i, lx, tx = typ(x);2804switch(tx)2805{2806case t_CLOSURE:2807closure_unlink(x);2808gen_unlink(closure_get_data(x));2809if (lg(x)==8) gen_unlink(closure_get_frame(x));2810break;2811case t_LIST:2812if (list_data(x)) gen_unlink(list_data(x));2813break;2814case t_VEC: case t_COL: case t_MAT: case t_ERROR:2815lx = lg(x);2816for (i = lontyp[tx]; i<lx; i++) gen_unlink(gel(x,i));2817}2818}28192820GEN2821copybin_unlink(GEN C)2822{2823long i, l , n, nold = s_relocs.n;2824GEN v, w, V, res;2825if (C)2826gen_unlink(C);2827else2828{ /* contents of all variables */2829long v, maxv = pari_var_next();2830for (v=0; v<maxv; v++)2831{2832entree *ep = varentries[v];2833if (!ep || !ep->value) continue;2834gen_unlink((GEN)ep->value);2835}2836}2837n = s_relocs.n-nold;2838v = cgetg(n+1, t_VECSMALL);2839for(i=0; i<n; i++)2840v[i+1] = (long) relocs[i];2841s_relocs.n = nold;2842w = vecsmall_uniq(v); l = lg(w);2843res = cgetg(3,t_VEC);2844V = cgetg(l, t_VEC);2845for(i=1; i<l; i++)2846{2847entree *ep = (entree*) w[i];2848gel(V,i) = strtoGENstr(ep->name);2849}2850gel(res,1) = vecsmall_copy(w);2851gel(res,2) = V;2852return res;2853}28542855/* e = t_VECSMALL of entree *ep [ addresses ],2856* names = t_VEC of strtoGENstr(ep.names),2857* Return hashtable : ep => is_entry(ep.name) */2858hashtable *2859hash_from_link(GEN e, GEN names, int use_stack)2860{2861long i, l = lg(e);2862hashtable *h = hash_create_ulong(l-1, use_stack);2863if (lg(names) != l) pari_err_DIM("hash_from_link");2864for (i = 1; i < l; i++)2865{2866char *s = GSTR(gel(names,i));2867hash_insert(h, (void*)e[i], (void*)fetch_entry(s));2868}2869return h;2870}28712872void2873bincopy_relink(GEN C, GEN V)2874{2875pari_sp av = avma;2876hashtable *table = hash_from_link(gel(V,1),gel(V,2),1);2877gen_relink(C, table);2878set_avma(av);2879}288028812882