[Rd] Speed improvement to evalList

luke at stat.uiowa.edu luke at stat.uiowa.edu
Mon Aug 23 17:57:54 CEST 2010


Thanks for the suggestion.  I'll try to have a look later in the week
unless someone else gets there sooner.

luke

On Mon, 23 Aug 2010, Radford Neal wrote:

> Regarding my suggesting speed improvement to evalList, Martin Morgan
> has commented by email to me that at one point an object is left
> unprotected when COPY_TAG is called, and has wondered whether that is
> safe.  I think it is safe, but the code can be changed to protect this
> as well, which actually simplifies things, and could be more robust to
> changes to the garbage collector.  The cost is that sometimes there is
> one more call of PROTECT and UNPROTECT, but with the speed improvement
> to these that I just posted, this is a minor issue.
>
> Martin has also pointed me to where you can get R sources via
> subversion, but while I figure that out, and how to post up "diffs"
> for changes, I'll put the revised evalList code below for anyone
> interested...
>
>    Radford Neal
>
> ----------------------------------------------------------------------
>
> /* Used in eval and applyMethod (object.c) for builtin primitives,
>   do_internal (names.c) for builtin .Internals
>   and in evalArgs.
>
>   'n' is the number of arguments already evaluated and hence not
>   passed to evalArgs and hence to here.
> */
> SEXP attribute_hidden evalList(SEXP el, SEXP rho, SEXP call, int n)
> {
>    SEXP head, tail, ev, h;
>
>    head = R_NilValue;
>
>    while (el != R_NilValue) {
> 	n++;
>
> 	if (CAR(el) == R_DotsSymbol) {
> 	    /* If we have a ... symbol, we look to see what it is bound to.
> 	     * If its binding is Null (i.e. zero length),
> 	     *	we just ignore it and return the cdr with all its expressions
>             *  evaluated.
> 	     * If it is bound to a ... list of promises,
> 	     *	we force all the promises and then splice
> 	     *	the list of resulting values into the return value.
> 	     * Anything else bound to a ... symbol is an error.
> 	     */
> 	    h = findVar(CAR(el), rho);
> 	    if (TYPEOF(h) == DOTSXP || h == R_NilValue) {
> 		while (h != R_NilValue) {
>                    ev = CONS(eval(CAR(h), rho), R_NilValue);
>                    if (head==R_NilValue)
>                        PROTECT(head = ev);
>                    else
>                        SETCDR(tail, ev);
>                    COPY_TAG(ev, h);
>                    tail = ev;
> 		    h = CDR(h);
> 		}
> 	    }
> 	    else if (h != R_MissingArg)
> 		error(_("'...' used in an incorrect context"));
> 	} else if (CAR(el) == R_MissingArg) {
> 	    /* It was an empty element: most likely get here from evalArgs
> 	       which may have been called on part of the args. */
> 	    errorcall(call, _("argument %d is empty"), n);
> 	} else if (isSymbol(CAR(el)) && R_isMissing(CAR(el), rho)) {
> 	    /* It was missing */
> 	    errorcall(call, _("'%s' is missing"), CHAR(PRINTNAME(CAR(el))));
> 	} else {
>            ev = CONS(eval(CAR(el), rho), R_NilValue);
>            if (head==R_NilValue)
>                PROTECT(head = ev);
>            else
>                SETCDR(tail, ev);
>            COPY_TAG(ev, el);
>            tail = ev;
> 	}
> 	el = CDR(el);
>    }
>
>    if (head!=R_NilValue)
>        UNPROTECT(1);
>
>    return head;
>
> } /* evalList() */
>
>
> /* A slight variation of evaluating each expression in "el" in "rho". */
>
> /* used in evalArgs, arithmetic.c, seq.c */
> SEXP attribute_hidden evalListKeepMissing(SEXP el, SEXP rho)
> {
>    SEXP head, tail, ev, h;
>
>    head = R_NilValue;
>
>    while (el != R_NilValue) {
>
> 	/* If we have a ... symbol, we look to see what it is bound to.
> 	 * If its binding is Null (i.e. zero length)
> 	 *	we just ignore it and return the cdr with all its expressions evaluated;
> 	 * if it is bound to a ... list of promises,
> 	 *	we force all the promises and then splice
> 	 *	the list of resulting values into the return value.
> 	 * Anything else bound to a ... symbol is an error
> 	*/
> 	if (CAR(el) == R_DotsSymbol) {
> 	    h = findVar(CAR(el), rho);
> 	    if (TYPEOF(h) == DOTSXP || h == R_NilValue) {
> 		while (h != R_NilValue) {
>                    if (CAR(h) == R_MissingArg)
>                        ev = CONS(R_MissingArg, R_NilValue);
>                    else
>                        ev = CONS(eval(CAR(h), rho), R_NilValue);
>                    if (head==R_NilValue)
>                        PROTECT(head = ev);
>                    else
>                        SETCDR(tail, ev);
>                    COPY_TAG(ev, h);
>                    tail = ev;
> 		    h = CDR(h);
> 		}
> 	    }
> 	    else if(h != R_MissingArg)
> 		error(_("'...' used in an incorrect context"));
> 	}
> 	else {
>            if (CAR(el) == R_MissingArg ||
>                 (isSymbol(CAR(el)) && R_isMissing(CAR(el), rho)))
>                ev = CONS(R_MissingArg, R_NilValue);
>            else
>                ev = CONS(eval(CAR(el), rho), R_NilValue);
>            if (head==R_NilValue)
>                PROTECT(head = ev);
>            else
>                SETCDR(tail, ev);
>            COPY_TAG(ev, el);
>            tail = ev;
> 	}
> 	el = CDR(el);
>    }
>
>    if (head!=R_NilValue)
>        UNPROTECT(1);
>
>    return head;
> }
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Luke Tierney
Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:      luke at stat.uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



More information about the R-devel mailing list