1 /* Call vips functions from the graph reducer.
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 */
23
24 /*
25
26 These files are distributed with CALL - http://www.vips.ecs.soton.ac.uk
27
28 */
29
30 #include "ip.h"
31
32 /*
33 #define DEBUG_TIME
34 #define DEBUG
35 */
36
37 /* This is usually turned on from a -D in cflags.
38 #define DEBUG_LEAK
39 */
40
41 /* Often want it off ... we get spurious complaints about leaks if an
42 * operation has no images in or out (eg. im_version) because it'll never
43 * get GCed.
44 #undef DEBUG_LEAK
45 */
46
47 /* CALL argument types we support. Keep order in sync with CallArgumentType.
48 */
49 static im_arg_type call_supported[] = {
50 IM_TYPE_DOUBLE,
51 IM_TYPE_INT,
52 IM_TYPE_COMPLEX,
53 IM_TYPE_STRING,
54 IM_TYPE_IMAGE,
55 IM_TYPE_DOUBLEVEC,
56 IM_TYPE_DMASK,
57 IM_TYPE_IMASK,
58 IM_TYPE_IMAGEVEC,
59 IM_TYPE_INTVEC,
60 IM_TYPE_GVALUE,
61 IM_TYPE_INTERPOLATE
62 };
63
64 static iObjectClass *parent_class = NULL;
65
66 /* All the CallInfo we make ... for leak and sanity testing. Build this file
67 * with DEBUG_LEAK to enable add/remove to this list.
68 */
69 GSList *call_info_all = NULL;
70
71 void
call_check_all_destroyed(void)72 call_check_all_destroyed( void )
73 {
74 #ifdef DEBUG_LEAK
75 int n_leaks;
76 GSList *p;
77
78 n_leaks = 0;
79 for( p = call_info_all; p; p = p->next ) {
80 CallInfo *vi = (CallInfo *) p->data;
81
82 /* Operations which don't take an image as either an input or
83 * output will stay in the cache. Don't report them.
84 */
85 if( vi->ninii || vi->noutii ) {
86 n_leaks += 1;
87 printf( "\t%s\n", vi->name );
88 }
89 }
90
91 if( n_leaks )
92 printf( "** %d CallInfo leaked!\n", n_leaks );
93 #endif /*DEBUG_LEAK*/
94 }
95
96 /* Does a vips argument type require an argument from nip2?
97 */
98 gboolean
call_type_needs_input(im_type_desc * ty)99 call_type_needs_input( im_type_desc *ty )
100 {
101 /* We supply these.
102 */
103 if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 )
104 return( FALSE );
105
106 if( !(ty->flags & IM_TYPE_OUTPUT) )
107 return( TRUE );
108
109 if( ty->flags & IM_TYPE_RW )
110 return( TRUE );
111
112 return( FALSE );
113 }
114
115 /* Will a vips argument type generate a result for nip2?
116 */
117 gboolean
call_type_makes_output(im_type_desc * ty)118 call_type_makes_output( im_type_desc *ty )
119 {
120 /* We ignore these.
121 */
122 if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 )
123 return( FALSE );
124
125 if( ty->flags & (IM_TYPE_OUTPUT | IM_TYPE_RW) )
126 return( TRUE );
127
128 return( FALSE );
129 }
130
131 /* Error early on .. we can't print args yet.
132 */
133 void
call_error(CallInfo * vi)134 call_error( CallInfo *vi )
135 {
136 error_top( _( "CALL library error." ) );
137 error_sub( _( "Error calling library function \"%s\" (%s)." ),
138 vi->name, vi->fn->desc );
139 }
140
141 /* Get the args from the heap.
142 */
143 static void
call_args_heap(CallInfo * vi,HeapNode ** arg,VipsBuf * buf)144 call_args_heap( CallInfo *vi, HeapNode **arg, VipsBuf *buf )
145 {
146 int i;
147
148 vips_buf_appendf( buf, _( "You passed:" ) );
149 vips_buf_appendf( buf, "\n" );
150 for( i = 0; i < vi->nargs; i++ ) {
151 im_arg_desc *varg = &vi->fn->argv[vi->inpos[i]];
152 PElement rhs;
153
154 PEPOINTRIGHT( arg[vi->nargs - i - 1], &rhs );
155 vips_buf_appendf( buf, " %s - ", varg->name );
156 itext_value_ev( vi->rc, buf, &rhs );
157 vips_buf_appendf( buf, "\n" );
158 }
159 }
160
161 /* Make a usage error for a CALL function.
162 */
163 void
call_usage(VipsBuf * buf,im_function * fn)164 call_usage( VipsBuf *buf, im_function *fn )
165 {
166 im_package *pack = im_package_of_function( fn->name );
167 char input[MAX_STRSIZE];
168 char output[MAX_STRSIZE];
169 int nout, nin;
170 int i;
171
172 strcpy( input, "" );
173 strcpy( output, "" );
174 nin = 0;
175 nout = 0;
176 for( i = 0; i < fn->argc; i++ ) {
177 im_arg_desc *arg = &fn->argv[i];
178 char line[256];
179
180 /* Format name, type message.
181 */
182 im_snprintf( line, 256,
183 " %s - %s\n", arg->name, arg->desc->type );
184
185 if( call_type_makes_output( arg->desc ) ) {
186 strcat( output, line );
187 nout++;
188 }
189
190 if( call_type_needs_input( arg->desc ) ) {
191 strcat( input, line );
192 nin++;
193 }
194 }
195
196 vips_buf_appendf( buf, _( "Usage:" ) );
197 vips_buf_appends( buf, "\n" );
198 vips_buf_appendf( buf, _( "CALL operator \"%s\"" ), fn->name );
199 vips_buf_appends( buf, "\n" );
200 vips_buf_appendf( buf, _( "%s, from package \"%s\"" ),
201 fn->desc, pack->name );
202 vips_buf_appends( buf, "\n" );
203
204 vips_buf_appendf( buf,
205 ngettext( "\"%s\" takes %d argument:",
206 "\"%s\" takes %d arguments:",
207 nin ),
208 fn->name, nin );
209 vips_buf_appendf( buf, "\n%s", input );
210
211 vips_buf_appendf( buf,
212 ngettext( "And produces %d result:",
213 "And produces %d results:",
214 nout ),
215 nout );
216 vips_buf_appendf( buf, "\n%s", output );
217
218 /* Print any flags this function has.
219 */
220 vips_buf_appendf( buf, _( "Flags:" ) );
221 vips_buf_appends( buf, "\n" );
222 vips_buf_appendf( buf, " (" );
223 if( fn->flags & IM_FN_PIO )
224 vips_buf_appendf( buf, _( "PIO function" ) );
225 else
226 vips_buf_appendf( buf, _( "WIO function" ) );
227 vips_buf_appendf( buf, ") (" );
228 if( fn->flags & IM_FN_TRANSFORM )
229 vips_buf_appendf( buf, _( "coordinate transformer" ) );
230 else
231 vips_buf_appendf( buf, _( "no coordinate transformation" ) );
232 vips_buf_appendf( buf, ") (" );
233 if( fn->flags & IM_FN_PTOP )
234 vips_buf_appendf( buf, _( "point-to-point operation" ) );
235 else
236 vips_buf_appendf( buf, _( "area operation" ) );
237 vips_buf_appendf( buf, ") (" );
238 if( fn->flags & IM_FN_NOCACHE )
239 vips_buf_appendf( buf, _( "uncacheable operation" ) );
240 else
241 vips_buf_appendf( buf, _( "operation can be cached" ) );
242 vips_buf_appendf( buf, ")\n" );
243 }
244
245 /* We know there's a problem exporting a particular arg to CALL.
246 */
247 static void
call_error_arg(CallInfo * vi,HeapNode ** arg,int argi)248 call_error_arg( CallInfo *vi, HeapNode **arg, int argi )
249 {
250 char txt[10000];
251 VipsBuf buf = VIPS_BUF_STATIC( txt );
252
253 error_top( _( "Bad argument." ) );
254
255 vips_buf_appendf( &buf,
256 _( "Argument %d (%s) to \"%s\" is the wrong type." ),
257 argi + 1, vi->fn->argv[vi->inpos[argi]].name, vi->name );
258 vips_buf_appendf( &buf, "\n" );
259 call_args_heap( vi, arg, &buf );
260 vips_buf_appendf( &buf, "\n" );
261 call_usage( &buf, vi->fn );
262 error_sub( "%s", vips_buf_all( &buf ) );
263 }
264
265 /* Too many args.
266 */
267 void
call_error_toomany(CallInfo * vi)268 call_error_toomany( CallInfo *vi )
269 {
270 char txt[1000];
271 VipsBuf buf = VIPS_BUF_STATIC( txt );
272
273 error_top( _( "Too many arguments." ) );
274
275 vips_buf_appendf( &buf,
276 _( "Too many arguments to \"%s\"." ),
277 vi->name );
278 vips_buf_appendf( &buf, "\n" );
279 call_usage( &buf, vi->fn );
280 error_sub( "%s", vips_buf_all( &buf ) );
281 }
282
283 /* Look up a CALL type.
284 */
285 CallArgumentType
call_lookup_type(im_arg_type type)286 call_lookup_type( im_arg_type type )
287 {
288 int i;
289
290 for( i = 0; i < IM_NUMBER( call_supported ); i++ )
291 if( strcmp( type, call_supported[i] ) == 0 )
292 return( (CallArgumentType) i );
293
294 error_top( _( "Unknown type." ) );
295 error_sub( _( "CALL type \"%s\" not supported" ), type );
296
297 return( CALL_NONE );
298 }
299
300 /* Is this the sort of CALL function we can call?
301 */
302 gboolean
call_is_callable(im_function * fn)303 call_is_callable( im_function *fn )
304 {
305 int i;
306 int nout;
307 int nin;
308
309 if( fn->argc >= MAX_CALL_ARGS )
310 return( FALSE );
311
312 /* Check all argument types are supported. As well as the arg types
313 * spotted by call_lookup_type, we also allow IM_TYPE_DISPLAY.
314 */
315 for( i = 0; i < fn->argc; i++ ) {
316 im_arg_desc *arg = &fn->argv[i];
317 im_arg_type vt = arg->desc->type;
318
319 if( call_lookup_type( vt ) == CALL_NONE ) {
320 /* Unknown type .. if DISPLAY it's OK.
321 */
322 if( strcmp( vt, IM_TYPE_DISPLAY ) != 0 )
323 return( FALSE );
324 }
325 }
326
327 nin = nout = 0;
328 for( i = 0; i < fn->argc; i++ ) {
329 im_type_desc *ty = fn->argv[i].desc;
330
331 if( call_type_makes_output( ty ) )
332 nout += 1;
333
334 if( call_type_needs_input( ty ) )
335 nin += 1;
336 }
337
338 /* Must be at least one output argument.
339 */
340
341 /* Must be at least one output argument.
342 */
343 if( nout == 0 )
344 return( FALSE );
345
346 /* Need at least 1 input argument: we reply on having an application
347 * node to overwrite with (I result).
348 */
349 if( nin == 0 )
350 return( FALSE );
351
352 return( TRUE );
353 }
354
355 /* Count the number of args a CALL function needs.
356 */
357 int
call_n_args(im_function * fn)358 call_n_args( im_function *fn )
359 {
360 int i;
361 int nin;
362
363 for( nin = 0, i = 0; i < fn->argc; i++ ) {
364 im_type_desc *ty = fn->argv[i].desc;
365
366 if( call_type_needs_input( ty ) )
367 nin += 1;
368 }
369
370 return( nin );
371 }
372
373 /* Make an im_doublevec_object.
374 */
375 static int
call_make_doublevec(im_doublevec_object * dv,int n,double * vec)376 call_make_doublevec( im_doublevec_object *dv, int n, double *vec )
377 {
378 int i;
379
380 dv->n = n;
381 dv->vec = NULL;
382
383 if( n > 0 ) {
384 if( !(dv->vec = IARRAY( NULL, n, double )) )
385 return( -1 );
386 for( i = 0; i < n; i++ )
387 dv->vec[i] = vec[i];
388 }
389
390 return( 0 );
391 }
392
393 /* Make an im_intvec_object. Make from a vec of doubles, because that's what
394 * we get from nip.
395 */
396 static int
call_make_intvec(im_intvec_object * dv,int n,double * vec)397 call_make_intvec( im_intvec_object *dv, int n, double *vec )
398 {
399 int i;
400
401 dv->n = n;
402 dv->vec = NULL;
403
404 if( n > 0 ) {
405 if( !(dv->vec = IARRAY( NULL, n, int )) )
406 return( -1 );
407 for( i = 0; i < n; i++ )
408 dv->vec[i] = vec[i];
409 }
410
411 return( 0 );
412 }
413
414 /* Make an im_imagevec_object.
415 */
416 static int
call_make_imagevec(im_imagevec_object * iv,int n)417 call_make_imagevec( im_imagevec_object *iv, int n )
418 {
419 int i;
420
421 iv->n = n;
422 iv->vec = NULL;
423
424 if( n > 0 ) {
425 if( !(iv->vec = IARRAY( NULL, n, IMAGE * )) )
426 return( -1 );
427 for( i = 0; i < n; i++ )
428 iv->vec[i] = NULL;
429 }
430
431 return( 0 );
432 }
433
434 /* Add another ii to inii.
435 */
436 static gboolean
call_add_input_ii(CallInfo * vi,Imageinfo * ii)437 call_add_input_ii( CallInfo *vi, Imageinfo *ii )
438 {
439 if( vi->ninii > MAX_CALL_ARGS ) {
440 call_error_toomany( vi );
441 return( FALSE );
442 }
443
444 vi->inii[vi->ninii] = ii;
445 vi->ninii += 1;
446
447 /* We hold a ref to the ii until the call is done and the result
448 * written back to nip2. If we cache the result, we make a new
449 * weakref.
450 */
451 managed_dup_nonheap( MANAGED( ii ) );
452 vi->must_drop = TRUE;
453
454 return( TRUE );
455 }
456
457 /* ip types -> CALL types. Write to obj. FALSE for no conversion possible.
458 */
459 static gboolean
call_fromip(CallInfo * vi,int i,PElement * arg)460 call_fromip( CallInfo *vi, int i, PElement *arg )
461 {
462 im_type_desc *ty = vi->fn->argv[i].desc;
463 CallArgumentType vt = call_lookup_type( ty->type );
464 im_object *obj = &vi->vargv[i];
465
466 /* If call_lookup_type failed, is it the special DISPLAY type?
467 */
468 if( vt == CALL_NONE && strcmp( ty->type, IM_TYPE_DISPLAY ) != 0 )
469 /* Unknown type, and it's not DISPLAY. Flag an error.
470 */
471 return( FALSE );
472
473 switch( vt ) {
474 case CALL_NONE: /* IM_TYPE_DISPLAY */
475 /* Just use IM_TYPE_sRGB.
476 */
477 *obj = im_col_displays( 7 );
478
479 break;
480
481 case CALL_DOUBLE:
482 {
483 double *a = *obj;
484
485 if( !PEISREAL( arg ) )
486 return( FALSE );
487 *a = PEGETREAL( arg );
488
489 break;
490 }
491
492 case CALL_INT:
493 {
494 int *i = *obj;
495
496 if( PEISREAL( arg ) ) {
497 double t = PEGETREAL( arg );
498
499 *i = (int) t;
500 }
501 else if( PEISBOOL( arg ) )
502 *i = PEGETBOOL( arg );
503 else
504 return( FALSE );
505
506 break;
507 }
508
509 case CALL_COMPLEX:
510 {
511 double *c = *obj;
512
513 if( !PEISCOMPLEX( arg ) )
514 return( FALSE );
515 c[0] = PEGETREALPART( arg );
516 c[1] = PEGETIMAGPART( arg );
517
518 break;
519 }
520
521 case CALL_STRING:
522 {
523 char **c = (char **) obj;
524 char buf[MAX_STRSIZE];
525
526 if( !heap_get_string( arg, buf, MAX_STRSIZE ) )
527 return( FALSE );
528 *c = im_strdup( NULL, buf );
529
530 break;
531 }
532
533 case CALL_IMAGE:
534 /* Just note the Imageinfo for now ... a later pass sets vargv
535 * once we've checked all the LUTs.
536 */
537 if( !PEISIMAGE( arg ) ||
538 !call_add_input_ii( vi, IMAGEINFO( PEGETII( arg ) ) ) )
539 return( FALSE );
540
541 break;
542
543 case CALL_DOUBLEVEC:
544 {
545 double buf[MAX_VEC];
546 int n;
547
548 if( (n = heap_get_realvec( arg, buf, MAX_VEC )) < 0 ||
549 call_make_doublevec( *obj, n, buf ) )
550 return( FALSE );
551
552 break;
553 }
554
555 case CALL_INTVEC:
556 {
557 double buf[MAX_VEC];
558 int n;
559
560 if( (n = heap_get_realvec( arg, buf, MAX_VEC )) < 0 ||
561 call_make_intvec( *obj, n, buf ) )
562 return( FALSE );
563
564 break;
565 }
566
567 case CALL_IMAGEVEC:
568 {
569 Imageinfo *buf[MAX_VEC];
570 int n;
571 int i;
572
573 /* Put Imageinfo in for now ... a later pass changes this to
574 * IMAGE* once we've checked all the LUTs.
575 */
576 if( (n = heap_get_imagevec( arg, buf, MAX_VEC )) < 0 ||
577 call_make_imagevec( *obj, n ) )
578 return( FALSE );
579
580 for( i = 0; i < n; i++ )
581 if( !call_add_input_ii( vi, buf[i] ) )
582 return( FALSE );
583
584 break;
585 }
586
587 case CALL_DMASK:
588 case CALL_IMASK:
589 {
590 im_mask_object **mo = (im_mask_object **) obj;
591
592 if( vt == 6 ) {
593 DOUBLEMASK *mask;
594
595 if( !(mask = matrix_ip_to_dmask( arg )) )
596 return( FALSE );
597 (*mo)->mask = mask;
598 (*mo)->name = im_strdupn( mask->filename );
599 }
600 else {
601 INTMASK *mask;
602
603 if( !(mask = matrix_ip_to_imask( arg )) )
604 return( FALSE );
605 (*mo)->mask = mask;
606 (*mo)->name = im_strdupn( mask->filename );
607 }
608
609 break;
610 }
611
612 case CALL_GVALUE:
613 {
614 GValue *value = *obj;
615
616 memset( value, 0, sizeof( GValue ) );
617 if( !heap_ip_to_gvalue( arg, value ) )
618 return( FALSE );
619
620 break;
621 }
622
623 case CALL_INTERPOLATE:
624 if( !PEISMANAGEDGOBJECT( arg ) )
625 return( FALSE );
626 *obj = PEGETMANAGEDGOBJECT( arg );
627
628 break;
629
630 default:
631 g_assert( FALSE );
632 }
633
634 return( TRUE );
635 }
636
637 /* CALL types -> ip types. Write to arg. Use outiiindex to iterate through
638 * outii[] as we find output imageinfo.
639 */
640 static gboolean
call_toip(CallInfo * vi,int i,int * outiiindex,PElement * arg)641 call_toip( CallInfo *vi, int i, int *outiiindex, PElement *arg )
642 {
643 im_object obj = vi->vargv[i];
644 im_type_desc *ty = vi->fn->argv[i].desc;
645
646 #ifdef DEBUG
647 printf( "call_toip: arg[%d] (%s) = ", i, ty->type );
648 #endif /*DEBUG*/
649
650 switch( call_lookup_type( ty->type ) ) {
651 case CALL_DOUBLE:
652 if( !heap_real_new( vi->rc->heap, *((double*)obj), arg ) )
653 return( FALSE );
654
655 break;
656
657 case CALL_INT:
658 if( !heap_real_new( vi->rc->heap, *((int*)obj), arg ) )
659 return( FALSE );
660
661 break;
662
663 case CALL_DOUBLEVEC:
664 {
665 im_doublevec_object *dv = obj;
666
667 if( !heap_realvec_new( vi->rc->heap, dv->n, dv->vec, arg ) )
668 return( FALSE );
669
670 break;
671 }
672
673 case CALL_INTVEC:
674 {
675 im_intvec_object *iv = obj;
676
677 if( !heap_intvec_new( vi->rc->heap, iv->n, iv->vec, arg ) )
678 return( FALSE );
679
680 break;
681 }
682
683 case CALL_COMPLEX:
684 if( !heap_complex_new( vi->rc->heap,
685 ((double*)obj)[0], ((double*)obj)[1], arg ) )
686 return( FALSE );
687
688 break;
689
690 case CALL_STRING:
691 if( !heap_managedstring_new( vi->rc->heap, (char *) obj, arg ) )
692 return( FALSE );
693
694 break;
695
696 case CALL_IMAGE:
697 {
698 Imageinfo *outii;
699
700 outii = vi->outii[*outiiindex];
701 *outiiindex += 1;
702
703 PEPUTP( arg, ELEMENT_MANAGED, outii );
704
705 break;
706 }
707
708 case CALL_DMASK:
709 {
710 im_mask_object *mo = obj;
711 DOUBLEMASK *mask = mo->mask;
712
713 if( !matrix_dmask_to_heap( vi->rc->heap, mask, arg ) )
714 return( FALSE );
715
716 break;
717 }
718
719 case CALL_IMASK:
720 {
721 im_mask_object *mo = obj;
722 INTMASK *mask = mo->mask;
723
724 if( !matrix_imask_to_heap( vi->rc->heap, mask, arg ) )
725 return( FALSE );
726
727 break;
728 }
729
730 case CALL_GVALUE:
731 if( !heap_gvalue_to_ip( (GValue *) obj, arg ) )
732 return( FALSE );
733
734 break;
735
736 case CALL_IMAGEVEC:
737 case CALL_INTERPOLATE:
738 default:
739 g_assert( FALSE );
740 }
741
742 #ifdef DEBUG
743 pgraph( arg );
744 #endif /*DEBUG*/
745
746 return( TRUE );
747 }
748
749 static void *
call_write_result_sub(Reduce * rc,PElement * safe,CallInfo * vi,PElement * out)750 call_write_result_sub( Reduce *rc, PElement *safe, CallInfo *vi, PElement *out )
751 {
752 int outiiindex;
753
754 /* call_toip() uses this to iterate through outii[].
755 */
756 outiiindex = 0;
757
758 /* Write result.
759 */
760 if( vi->nres == 1 ) {
761 /* Single result.
762 */
763 if( !call_toip( vi, vi->outpos[0], &outiiindex, safe ) )
764 return( out );
765 }
766 else {
767 /* Have to build a list of results.
768 */
769 PElement list;
770 PElement t;
771 int i;
772
773 list = *safe;
774 heap_list_init( &list );
775 for( i = 0; i < vi->nres; i++ ) {
776 if( !heap_list_add( vi->rc->heap, &list, &t ) ||
777 !call_toip( vi,
778 vi->outpos[i], &outiiindex, &t ) )
779 return( out );
780
781 (void) heap_list_next( &list );
782 }
783 }
784
785 /* Now overwrite out with safe.
786 */
787 PEPUTPE( out, safe );
788
789 return( NULL );
790 }
791
792 /* Write the results back to the heap. We have to so this in two stages:
793 * build the output object linked off a new managed Element, then once it's
794 * built, overwrite our output
795 */
796 static gboolean
call_write_result(CallInfo * vi,PElement * out)797 call_write_result( CallInfo *vi, PElement *out )
798 {
799 if( reduce_safe_pointer( vi->rc,
800 (reduce_safe_pointer_fn) call_write_result_sub,
801 vi, out, NULL, NULL ) )
802 return( FALSE );
803
804 return( TRUE );
805 }
806
807 /* Junk all the refs we were holding during the call. See call_add_input_ii()
808 * and call_add_output_ii().
809 *
810 * This gets called explicitly after we have handed the ii refs back to nip2
811 * during normal processing, or from _dispose() if we bomb out early and
812 * unref.
813 */
814 static void
call_drop_refs(CallInfo * vi)815 call_drop_refs( CallInfo *vi )
816 {
817 if( vi->must_drop ) {
818 int i;
819
820 #ifdef DEBUG
821 printf( "call_drop_refs: dropping %d in refs\n", vi->ninii );
822 printf( "call_drop_refs: dropping %d out refs\n", vi->noutii );
823 #endif /*DEBUG*/
824
825 for( i = 0; i < vi->ninii; i++ )
826 managed_destroy_nonheap( MANAGED( vi->inii[i] ) );
827 for( i = 0; i < vi->noutii; i++ )
828 managed_destroy_nonheap( MANAGED( vi->outii[i] ) );
829
830 vi->must_drop = FALSE;
831 }
832 }
833
834 static void
call_info_dispose(GObject * gobject)835 call_info_dispose( GObject *gobject )
836 {
837 CallInfo *vi;
838
839 g_return_if_fail( gobject != NULL );
840 g_return_if_fail( IS_CALL_INFO( gobject ) );
841
842 vi = CALL_INFO( gobject );
843
844 #ifdef DEBUG
845 printf( "call_info_dispose: (%p) %s \"%s\"\n",
846 vi, G_OBJECT_TYPE_NAME( vi ), vi->name );
847 #endif /*DEBUG*/
848
849 /* Are we in the history? Remove us.
850 */
851 cache_history_remove( vi );
852
853 /* Drop any refs we may have left dangling.
854 */
855 call_drop_refs( vi );
856
857 G_OBJECT_CLASS( parent_class )->dispose( gobject );
858 }
859
860 /* Junk stuff we may have attached to vargv.
861 */
862 static void
call_vargv_free(im_function * fn,im_object * vargv)863 call_vargv_free( im_function *fn, im_object *vargv )
864 {
865 int i;
866
867 /* Free any CALL args we built and haven't used.
868 */
869 for( i = 0; i < fn->argc; i++ ) {
870 im_type_desc *ty = fn->argv[i].desc;
871 im_object *obj = vargv[i];
872 CallArgumentType vt;
873
874 /* Make sure we don't damage any error message we might
875 * have.
876 */
877 error_block();
878 vt = call_lookup_type( ty->type );
879 error_unblock();
880
881 switch( vt ) {
882 case CALL_NONE: /* IM_TYPE_DISPLAY */
883 case CALL_DOUBLE:
884 case CALL_INT:
885 case CALL_COMPLEX:
886 case CALL_GVALUE:
887 case CALL_INTERPOLATE:
888 case CALL_IMAGE:
889 /* Do nothing.
890 */
891 break;
892
893 case CALL_STRING:
894 IM_FREE( obj );
895 break;
896
897 case CALL_IMAGEVEC:
898 IM_FREE( ((im_imagevec_object *) obj)->vec );
899 break;
900
901 case CALL_DOUBLEVEC:
902 IM_FREE( ((im_doublevec_object *) obj)->vec );
903 break;
904
905 case CALL_INTVEC:
906 IM_FREE( ((im_intvec_object *) obj)->vec );
907 break;
908
909 case CALL_DMASK:
910 IM_FREE( ((im_mask_object *) obj)->name );
911 IM_FREEF( im_free_dmask,
912 ((im_mask_object *) obj)->mask );
913 break;
914
915 case CALL_IMASK:
916 IM_FREE( ((im_mask_object *) obj)->name );
917 IM_FREEF( im_free_imask,
918 ((im_mask_object *) obj)->mask );
919 break;
920
921 default:
922 g_assert( FALSE );
923 }
924 }
925 }
926
927 static void
call_info_finalize(GObject * gobject)928 call_info_finalize( GObject *gobject )
929 {
930 CallInfo *vi;
931
932 g_return_if_fail( gobject != NULL );
933 g_return_if_fail( IS_CALL_INFO( gobject ) );
934
935 vi = CALL_INFO( gobject );
936
937 #ifdef DEBUG_LEAK
938 call_info_all = g_slist_remove( call_info_all, vi );
939 #endif /*DEBUG_LEAK*/
940
941 if( vi->vargv ) {
942 call_vargv_free( vi->fn, vi->vargv );
943 im_free_vargv( vi->fn, vi->vargv );
944 IM_FREE( vi->vargv );
945 }
946
947 G_OBJECT_CLASS( parent_class )->finalize( gobject );
948 }
949
950 static void
call_info_info(iObject * iobject,VipsBuf * buf)951 call_info_info( iObject *iobject, VipsBuf *buf )
952 {
953 CallInfo *vi = CALL_INFO( iobject );
954
955 vips_buf_appendf( buf, "call_info_info: (%p) %s \"%s\"\n",
956 vi, G_OBJECT_TYPE_NAME( vi ), NN( IOBJECT( vi )->name ) );
957 }
958
959 static void
call_info_class_init(CallInfoClass * class)960 call_info_class_init( CallInfoClass *class )
961 {
962 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
963 iObjectClass *iobject_class = IOBJECT_CLASS( class );
964
965 parent_class = g_type_class_peek_parent( class );
966
967 gobject_class->dispose = call_info_dispose;
968 gobject_class->finalize = call_info_finalize;
969
970 iobject_class->info = call_info_info;
971 }
972
973 static void
call_info_init(CallInfo * vi)974 call_info_init( CallInfo *vi )
975 {
976 int i;
977
978 vi->name = NULL;
979 vi->fn = NULL;
980 vi->rc = NULL;
981 vi->vargv = NULL;
982 vi->nargs = 0;
983 vi->nres = 0;
984 vi->nires = 0;
985 vi->ninii = 0;
986 vi->noutii = 0;
987 vi->use_lut = FALSE; /* Set this properly later */
988 vi->found_hash = FALSE;
989 vi->in_cache = FALSE;
990 vi->must_drop = FALSE;
991
992 #ifdef DEBUG_LEAK
993 call_info_all = g_slist_prepend( call_info_all, vi );
994 #endif /*DEBUG_LEAK*/
995
996 for( i = 0; i < MAX_CALL_ARGS; i++ ) {
997 vi->outii_destroy_sid[i] = 0;
998 vi->inii_destroy_sid[i] = 0;
999 vi->inii_invalidate_sid[i] = 0;
1000 }
1001 }
1002
1003 GType
call_info_get_type(void)1004 call_info_get_type( void )
1005 {
1006 static GType type = 0;
1007
1008 if( !type ) {
1009 static const GTypeInfo info = {
1010 sizeof( CallInfoClass ),
1011 NULL, /* base_init */
1012 NULL, /* base_finalize */
1013 (GClassInitFunc) call_info_class_init,
1014 NULL, /* class_finalize */
1015 NULL, /* class_data */
1016 sizeof( CallInfo ),
1017 32, /* n_preallocs */
1018 (GInstanceInitFunc) call_info_init,
1019 };
1020
1021 type = g_type_register_static( TYPE_IOBJECT,
1022 "CallInfo", &info, 0 );
1023 }
1024
1025 return( type );
1026 }
1027
1028 static CallInfo *
call_new(Reduce * rc,im_function * fn)1029 call_new( Reduce *rc, im_function *fn )
1030 {
1031 CallInfo *vi;
1032 int i;
1033
1034 g_assert( fn->argc < MAX_CALL_ARGS - 1 );
1035
1036 if( !fn ||
1037 !(vi = CALL_INFO( g_object_new( TYPE_CALL_INFO, NULL ) )) )
1038 return( NULL );
1039 vi->name = fn->name;
1040 vi->fn = fn;
1041 vi->rc = rc;
1042
1043 /* Look over the args ... count the number of inputs we need, and
1044 * the number of outputs we generate. Note the position of each.
1045 */
1046 for( i = 0; i < vi->fn->argc; i++ ) {
1047 im_type_desc *ty = vi->fn->argv[i].desc;
1048
1049 if( call_type_makes_output( ty ) ) {
1050 vi->outpos[vi->nres] = i;
1051 vi->nres += 1;
1052
1053 /* Image output.
1054 */
1055 if( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 )
1056 vi->nires += 1;
1057 }
1058
1059 if( call_type_needs_input( ty ) ) {
1060 vi->inpos[vi->nargs] = i;
1061 vi->nargs += 1;
1062 }
1063 }
1064
1065 /* Make the call spine, alloc memory.
1066 */
1067 if( !(vi->vargv = IM_ARRAY( NULL, vi->fn->argc + 1, im_object )) ||
1068 im_allocate_vargv( vi->fn, vi->vargv ) ) {
1069 call_error( vi );
1070 g_object_unref( vi );
1071 return( NULL );
1072 }
1073
1074 return( vi );
1075 }
1076
1077 /* Add another ii to outii.
1078 */
1079 static gboolean
call_add_output_ii(CallInfo * vi,Imageinfo * ii)1080 call_add_output_ii( CallInfo *vi, Imageinfo *ii )
1081 {
1082 if( vi->noutii > MAX_CALL_ARGS ) {
1083 call_error_toomany( vi );
1084 return( FALSE );
1085 }
1086
1087 vi->outii[vi->noutii] = ii;
1088 vi->noutii += 1;
1089
1090 /* We hold a ref to the ii until the call is done and the result
1091 * written back to nip2. If we cache the result, we make a new
1092 * weakref.
1093 */
1094 managed_dup_nonheap( MANAGED( ii ) );
1095 vi->must_drop = TRUE;
1096
1097 return( TRUE );
1098 }
1099
1100 /* Init an output slot in vargv.
1101 */
1102 static gboolean
call_build_output(CallInfo * vi,int i)1103 call_build_output( CallInfo *vi, int i )
1104 {
1105 im_type_desc *ty = vi->fn->argv[i].desc;
1106
1107 /* Provide output objects for the function to write to.
1108 */
1109 switch( call_lookup_type( ty->type ) ) {
1110 case CALL_DOUBLE:
1111 case CALL_INT:
1112 case CALL_COMPLEX:
1113 case CALL_STRING:
1114 break;
1115
1116 case CALL_IMAGE:
1117 {
1118 Imageinfo *ii;
1119
1120 if( !(ii = imageinfo_new_temp( main_imageinfogroup,
1121 vi->rc->heap, NULL, "p" )) ||
1122 !call_add_output_ii( vi, ii ) ||
1123 !(vi->vargv[i] = imageinfo_get( FALSE, ii )) )
1124 return( FALSE );
1125
1126 break;
1127 }
1128
1129 case CALL_DMASK:
1130 case CALL_IMASK:
1131 {
1132 im_mask_object *mo = vi->vargv[i];
1133
1134 mo->mask = NULL;
1135 mo->name = im_strdup( NULL, "" );
1136
1137 break;
1138 }
1139
1140 case CALL_GVALUE:
1141 {
1142 GValue *value = vi->vargv[i];
1143
1144 memset( value, 0, sizeof( GValue ) );
1145
1146 break;
1147 }
1148
1149 case CALL_DOUBLEVEC:
1150 case CALL_INTVEC:
1151 {
1152 /* intvec is also int + pointer.
1153 */
1154 im_doublevec_object *dv = vi->vargv[i];
1155
1156 dv->n = 0;
1157 dv->vec = NULL;
1158
1159 break;
1160 }
1161
1162 default:
1163 g_assert( FALSE );
1164 }
1165
1166 return( TRUE );
1167 }
1168
1169 static gboolean
call_build_inputva(CallInfo * vi,int i,va_list * ap)1170 call_build_inputva( CallInfo *vi, int i, va_list *ap )
1171 {
1172 im_type_desc *ty = vi->fn->argv[i].desc;
1173
1174 switch( call_lookup_type( ty->type ) ) {
1175 case CALL_DOUBLE:
1176 {
1177 double v = va_arg( *ap, double );
1178
1179 #ifdef DEBUG
1180 printf( "%g\n", v );
1181 #endif /*DEBUG*/
1182
1183 *((double*)vi->vargv[i]) = v;
1184
1185 if( trace_flags & TRACE_VIPS )
1186 vips_buf_appendf( trace_current(), "%g ", v );
1187
1188 break;
1189 }
1190
1191 case CALL_INT:
1192 {
1193 int v = va_arg( *ap, int );
1194
1195 #ifdef DEBUG
1196 printf( "%d\n", v );
1197 #endif /*DEBUG*/
1198
1199 *((int*)vi->vargv[i]) = v;
1200
1201 if( trace_flags & TRACE_VIPS )
1202 vips_buf_appendf( trace_current(), "%d ", v );
1203
1204 break;
1205 }
1206
1207 case CALL_GVALUE:
1208 {
1209 GValue *value = va_arg( *ap, GValue * );
1210
1211 #ifdef DEBUG
1212 printf( "gvalue %p\n", value );
1213 #endif /*DEBUG*/
1214
1215 vi->vargv[i] = value;
1216
1217 if( trace_flags & TRACE_VIPS ) {
1218 vips_buf_appendgv( trace_current(), value );
1219 vips_buf_appends( trace_current(), " " );
1220 }
1221
1222 break;
1223 }
1224
1225 case CALL_INTERPOLATE:
1226 {
1227 VipsInterpolate *value =
1228 va_arg( *ap, VipsInterpolate * );
1229
1230 #ifdef DEBUG
1231 printf( "interpolate %p\n", value );
1232 #endif /*DEBUG*/
1233
1234 vi->vargv[i] = value;
1235
1236 if( trace_flags & TRACE_VIPS ) {
1237 vips_object_to_string( VIPS_OBJECT( value ),
1238 trace_current() );
1239 vips_buf_appends( trace_current(), " " );
1240 }
1241
1242 break;
1243 }
1244
1245 case CALL_IMAGE:
1246 {
1247 Imageinfo *ii = va_arg( *ap, Imageinfo * );
1248
1249 #ifdef DEBUG
1250 printf( "imageinfo %p\n", ii );
1251 #endif /*DEBUG*/
1252
1253 if( !call_add_input_ii( vi, ii ) )
1254 return( FALSE );
1255
1256 /* Filled in later.
1257 */
1258 vi->vargv[i] = NULL;
1259
1260 if( trace_flags & TRACE_VIPS ) {
1261 VipsBuf *buf = trace_current();
1262
1263 if( ii && ii->im ) {
1264 vips_buf_appends( buf, "<" );
1265 vips_buf_appendf( buf,
1266 _( "image \"%s\"" ),
1267 ii->im->filename );
1268 vips_buf_appends( buf, "> " );
1269 }
1270 else {
1271 vips_buf_appends( buf, "<" );
1272 vips_buf_appends( buf,
1273 _( "no image" ) );
1274 vips_buf_appends( buf, "> " );
1275 }
1276 }
1277
1278 break;
1279 }
1280
1281 case CALL_DOUBLEVEC:
1282 {
1283 int n = va_arg( *ap, int );
1284 double *vec = va_arg( *ap, double * );
1285
1286 #ifdef DEBUG
1287 {
1288 int i;
1289
1290 for( i = 0; i < n; i++ )
1291 printf( "%g, ", vec[i] );
1292 printf( "\n" );
1293 }
1294 #endif /*DEBUG*/
1295
1296 if( call_make_doublevec( vi->vargv[i], n, vec ) )
1297 return( FALSE );
1298
1299 if( trace_flags & TRACE_VIPS ) {
1300 VipsBuf *buf = trace_current();
1301 int i;
1302
1303 vips_buf_appendf( buf, "<" );
1304 vips_buf_appendf( buf, _( "doublevec" ) );
1305 for( i = 0; i < n; i++ )
1306 vips_buf_appendf( buf, " %g", vec[i] );
1307 vips_buf_appends( buf, "> " );
1308 }
1309
1310 break;
1311 }
1312
1313 /*
1314
1315 FIXME ... add intvec perhaps
1316
1317 */
1318
1319 case CALL_IMAGEVEC:
1320 {
1321 int n = va_arg( *ap, int );
1322 Imageinfo **vec = va_arg( *ap, Imageinfo ** );
1323
1324 #ifdef DEBUG
1325 {
1326 int i;
1327
1328 for( i = 0; i < n; i++ )
1329 printf( "%p, ", vec[i] );
1330 printf( "\n" );
1331 }
1332 #endif /*DEBUG*/
1333
1334 if( call_make_imagevec( vi->vargv[i], n ) )
1335 return( FALSE );
1336
1337 for( i = 0; i < n; i++ )
1338 if( !call_add_input_ii( vi, vec[i] ) )
1339 return( FALSE );
1340
1341 if( trace_flags & TRACE_VIPS ) {
1342 VipsBuf *buf = trace_current();
1343 int i;
1344
1345 vips_buf_appendf( buf, "<" );
1346 vips_buf_appendf( buf, _( "imagevec" ) );
1347 for( i = 0; i < n; i++ ) {
1348 vips_buf_appendf( buf, " <" );
1349 vips_buf_appendf( buf,
1350 _( "image \"%s\"" ),
1351 vec[i]->im->filename );
1352 vips_buf_appendf( buf, ">" );
1353 }
1354 vips_buf_appends( buf, "> " );
1355 }
1356
1357 break;
1358 }
1359
1360 default:
1361 g_assert( FALSE );
1362 }
1363
1364 return( TRUE );
1365 }
1366
1367 /* Fill an argument vector from the C stack.
1368 */
1369 static gboolean
call_fillva(CallInfo * vi,va_list * ap)1370 call_fillva( CallInfo *vi, va_list *ap )
1371 {
1372 int i;
1373
1374 g_assert( vi->ninii == 0 );
1375 g_assert( vi->noutii == 0 );
1376
1377 for( i = 0; i < vi->fn->argc; i++ ) {
1378 im_type_desc *ty = vi->fn->argv[i].desc;
1379
1380 #ifdef DEBUG
1381 printf( "call_fillva: arg[%d] (%s) = ", i, ty->type );
1382 #endif /*DEBUG*/
1383
1384 if( call_type_makes_output( ty ) ) {
1385 if( !call_build_output( vi, i ) )
1386 return( FALSE );
1387 #ifdef DEBUG
1388 printf( " output\n" );
1389 #endif /*DEBUG*/
1390 }
1391
1392 if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) {
1393 /* DISPLAY argument ... just IM_TYPE_sRGB.
1394 */
1395 vi->vargv[i] = im_col_displays( 7 );
1396
1397 #ifdef DEBUG
1398 printf( " display\n" );
1399 #endif /*DEBUG*/
1400 }
1401
1402 if( call_type_needs_input( ty ) ) {
1403 if( !call_build_inputva( vi, i, ap ) )
1404 return( FALSE );
1405 }
1406 }
1407
1408 /* Every output ii depends upon all of the input ii.
1409 */
1410 for( i = 0; i < vi->noutii; i++ )
1411 managed_sub_add_all( MANAGED( vi->outii[i] ),
1412 vi->ninii, (Managed **) vi->inii );
1413
1414 #ifdef DEBUG
1415 printf( "call_fill_spine: reffed %d in\n", vi->ninii );
1416 printf( "call_fill_spine: created %d out\n", vi->noutii );
1417 #endif /*DEBUG*/
1418
1419 return( TRUE );
1420 }
1421
1422 static gboolean
callva_sub(Reduce * rc,const char * name,PElement * out,va_list * ap)1423 callva_sub( Reduce *rc, const char *name, PElement *out, va_list *ap )
1424 {
1425 CallInfo *vi;
1426 gboolean result;
1427
1428 if( trace_flags & TRACE_VIPS )
1429 trace_push();
1430
1431 if( !(vi = call_new( rc, im_find_function( name ) )) )
1432 return( FALSE );
1433
1434 if( trace_flags & TRACE_VIPS )
1435 vips_buf_appendf( trace_current(), "\"%s\" ", vi->name );
1436
1437 result = TRUE;
1438
1439 if( !call_fillva( vi, ap ) )
1440 result = FALSE;
1441
1442 if( trace_flags & TRACE_VIPS )
1443 vips_buf_appends( trace_current(), " ->\n" );
1444
1445 if( result && (
1446 !(vi = cache_dispatch( vi, out )) ||
1447 !call_write_result( vi, out ) ) )
1448 result = FALSE;
1449
1450 if( trace_flags & TRACE_VIPS ) {
1451 trace_result( TRACE_VIPS, out );
1452 trace_pop();
1453 }
1454
1455 if( vi ) {
1456 /* We must drop refs explicitly, since this unref might not
1457 * dispose the vi.
1458 */
1459 call_drop_refs( vi );
1460
1461 g_object_unref( vi );
1462 }
1463
1464 return( result );
1465 }
1466
1467 /* Call a CALL function picking up args from the function call.
1468 */
1469 void
callva(Reduce * rc,PElement * out,const char * name,...)1470 callva( Reduce *rc, PElement *out, const char *name, ... )
1471 {
1472 va_list ap;
1473 gboolean result;
1474
1475 #ifdef DEBUG
1476 printf( "** callva: starting for %s\n", name );
1477 #endif /*DEBUG*/
1478
1479 va_start( ap, name );
1480 result = callva_sub( rc, name, out, &ap );
1481 va_end( ap );
1482
1483 #ifdef DEBUG
1484 printf( "callva: done\n" );
1485 #endif /*DEBUG*/
1486
1487 if( !result )
1488 reduce_throw( rc );
1489 }
1490
1491 /* Fill an argument vector from our stack frame. Number of args already
1492 * checked.
1493 */
1494 static gboolean
call_fill_spine(CallInfo * vi,HeapNode ** arg)1495 call_fill_spine( CallInfo *vi, HeapNode **arg )
1496 {
1497 int i, j;
1498
1499 g_assert( vi->ninii == 0 );
1500 g_assert( vi->noutii == 0 );
1501
1502 /* Fully reduce all arguments. Once we've done this, we can be sure
1503 * there will not be a GC while we gather, and therefore that no
1504 * pointers will become invalid during this call.
1505 */
1506 for( i = 0; i < vi->nargs; i++ ) {
1507 PElement rhs;
1508
1509 PEPOINTRIGHT( arg[i], &rhs );
1510 if( !heap_reduce_strict( &rhs ) )
1511 return( FALSE );
1512 }
1513
1514 for( j = 0, i = 0; i < vi->fn->argc; i++ ) {
1515 im_type_desc *ty = vi->fn->argv[i].desc;
1516
1517 if( call_type_makes_output( ty ) )
1518 if( !call_build_output( vi, i ) )
1519 return( FALSE );
1520
1521 if( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) {
1522 /* Special DISPLAY argument - don't fetch another ip
1523 * argument for it.
1524 */
1525 (void) call_fromip( vi, i, NULL );
1526 }
1527
1528 if( call_type_needs_input( ty ) ) {
1529 PElement rhs;
1530
1531 /* Convert ip type to CALL type.
1532 */
1533 PEPOINTRIGHT( arg[vi->nargs - j - 1], &rhs );
1534 if( !call_fromip( vi, i, &rhs ) ) {
1535 call_error_arg( vi, arg, j );
1536 return( FALSE );
1537 }
1538
1539 j += 1;
1540 }
1541 }
1542
1543 /* Every output ii depends upon all of the input ii.
1544 */
1545 for( i = 0; i < vi->noutii; i++ )
1546 managed_sub_add_all( MANAGED( vi->outii[i] ),
1547 vi->ninii, (Managed **) vi->inii );
1548
1549 #ifdef DEBUG
1550 printf( "call_fill_spine: reffed %d inii\n", vi->ninii );
1551 printf( "call_fill_spine: created %d outii\n", vi->noutii );
1552 #endif /*DEBUG*/
1553
1554 return( TRUE );
1555 }
1556
1557 static gboolean
call_spine_sub(Reduce * rc,const char * name,im_function * fn,PElement * out,HeapNode ** arg)1558 call_spine_sub( Reduce *rc, const char *name, im_function *fn,
1559 PElement *out, HeapNode **arg )
1560 {
1561 CallInfo *vi;
1562 gboolean result;
1563
1564 #ifdef DEBUG
1565 printf( "** call_spine: starting for %s\n", name );
1566 #endif /*DEBUG*/
1567
1568 if( !(vi = call_new( rc, fn )) )
1569 return( FALSE );
1570
1571 if( trace_flags & TRACE_VIPS ) {
1572 VipsBuf *buf = trace_push();
1573
1574 vips_buf_appendf( buf, "\"%s\" ", name );
1575 trace_args( arg, vi->nargs );
1576 }
1577
1578 result = TRUE;
1579
1580 if( !call_fill_spine( vi, arg ) ||
1581 !(vi = cache_dispatch( vi, out )) ||
1582 !call_write_result( vi, out ) )
1583 result = FALSE;
1584
1585 if( trace_flags & TRACE_VIPS ) {
1586 trace_result( TRACE_VIPS, out );
1587 trace_pop();
1588 }
1589
1590 if( vi ) {
1591 /* We must drop refs explicitly, since this unref might not
1592 * dispose the vi.
1593 */
1594 call_drop_refs( vi );
1595
1596 g_object_unref( vi );
1597 }
1598
1599 #ifdef DEBUG
1600 printf( "call_spine: done\n" );
1601 #endif /*DEBUG*/
1602
1603 return( result );
1604 }
1605
1606 /* Call a CALL function, pick up args from the graph.
1607 */
1608 void
call_spine(Reduce * rc,const char * name,HeapNode ** arg,PElement * out)1609 call_spine( Reduce *rc, const char *name, HeapNode **arg, PElement *out )
1610 {
1611 if( !call_spine_sub( rc, name, im_find_function( name ), out, arg ) )
1612 reduce_throw( rc );
1613 }
1614
1615 /* As an ActionFn.
1616 */
1617 void
call_run(Reduce * rc,Compile * compile,int op,const char * name,HeapNode ** arg,PElement * out,im_function * function)1618 call_run( Reduce *rc, Compile *compile,
1619 int op, const char *name, HeapNode **arg, PElement *out,
1620 im_function *function )
1621 {
1622 if( !call_spine_sub( rc, name, function, out, arg ) )
1623 reduce_throw( rc );
1624 }
1625