1 /*
2  * Copyright © 1988-2004 Keith Packard and Bart Massey.
3  * All Rights Reserved.  See the file COPYING in this directory
4  * for licensing information.
5  */
6 
7 #include	"nickle.h"
8 #include	<assert.h>
9 
10 #undef DEBUG_FRAME
11 
12 #define Stack(i) ((Value) STACK_ELT(thread->thread.continuation.stack, i))
13 #define CStack(i)   ((Value) STACK_ELT(cstack, i))
14 
15 /*
16  * Instruction must be completed because changes have been
17  * committed to storage.
18  */
19 
20 Bool	complete;
21 
22 Bool	signalFinished;	    /* current thread is finished */
23 Bool	signalSuspend;	    /* current thread is suspending */
24 
25 #define Arg(n)	((n) <= base ? CStack(base - (n)) : value)
26 
27 static FramePtr
BuildFrame(Value thread,Value func,Value value,Bool staticInit,Bool tail,Bool varargs,int nformal,int base,int argc,InstPtr savePc,ObjPtr saveObj)28 BuildFrame (Value thread, Value func, Value value, Bool staticInit, Bool tail,
29 	    Bool varargs, int nformal,
30 	    int base, int argc, InstPtr savePc, ObjPtr saveObj)
31 {
32     ENTER ();
33     CodePtr	    code = func->func.code;
34     FuncBodyPtr	    body = staticInit ? &code->func.staticInit : &code->func.body;
35     StackObject	    *cstack = thread->thread.continuation.stack;
36     int		    fe;
37     FramePtr	    frame;
38 
39 #ifdef DEBUG_FRAME
40     FilePrintf (FileStdout, "BuildFrame func %v value %v\n", func, value);
41     ThreadStackDump (thread);
42     FileFlush (FileStdout, True);
43 #endif
44     frame = thread->thread.continuation.frame;
45     if (tail)
46 	frame = frame->previous;
47     frame = NewFrame (func, frame,
48 		      func->func.staticLink,
49 		      body->dynamics,
50 		      func->func.statics);
51     for (fe = 0; fe < nformal; fe++)
52 	BoxValueSet (frame->frame, fe, Copy (Arg(fe)));
53     if (varargs)
54     {
55 	int	extra = argc - nformal;
56 	Value	array;
57 
58 	array = NewArray (True, False, typePoly, 1, &extra);
59 	BoxValueSet (frame->frame, fe, array);
60 	for (; fe < argc; fe++)
61 	    ArrayValueSet (&array->array, fe-nformal, Copy (Arg(fe)));
62     }
63     if (tail)
64     {
65 	frame->savePc = thread->thread.continuation.frame->savePc;
66 	frame->saveObj = thread->thread.continuation.frame->saveObj;
67     }
68     else
69     {
70 	frame->savePc = savePc;
71 	frame->saveObj = saveObj;
72     }
73     RETURN (frame);
74 }
75 
76 static Value
ThreadCall(Value thread,Bool tail,InstPtr * next,int * stack)77 ThreadCall (Value thread, Bool tail, InstPtr *next, int *stack)
78 {
79     ENTER ();
80     int		argc = *stack;
81     Value	value = thread->thread.continuation.value;
82     StackObject *cstack = thread->thread.continuation.stack;
83     Value	func;
84     CodePtr	code;
85     FramePtr	frame;
86     ArgType	*argt;
87     int		fe;
88     int		base;
89 
90     /*
91      * Typecheck actuals
92      */
93     fe = 0;
94     base = argc - 2;
95     if (argc < 0)
96     {
97 	Value	numvar = Arg(0);
98 
99 	if (!ValueIsInt (numvar))
100 	{
101 	    RaiseStandardException (exception_invalid_argument, 3,
102 				    NewStrString ("Incompatible argument"),
103 				    NewInt(-1), Arg(0));
104 	    RETURN (Void);
105 	}
106 	argc = -argc - 1 + ValueInt(numvar);
107 	base = argc - 1;
108 	*stack = 1 + argc;  /* count + args */
109 	func = CStack(argc);
110     }
111     else
112 	func = argc ? CStack(argc-1) : value;
113     if (!ValueIsFunc(func))
114     {
115 	ThreadStackDump (thread);
116 	RaiseStandardException (exception_invalid_unop_value, 1, func);
117 	RETURN (Void);
118     }
119     code = func->func.code;
120     argt = code->base.args;
121     while (fe < argc || (argt && !argt->varargs))
122     {
123 	if (!argt)
124 	{
125 	    RaiseStandardException (exception_invalid_argument, 3,
126 				    NewStrString ("Too many arguments"),
127 				    NewInt (argc), NewInt(code->base.argc));
128 	    RETURN (Void);
129 	}
130 	if (fe == argc)
131 	{
132 	    RaiseStandardException (exception_invalid_argument, 3,
133 				    NewStrString ("Too few arguments"),
134 				    NewInt (argc), NewInt(code->base.argc));
135 	    RETURN (Void);
136 	}
137 	if (!TypeCompatibleAssign (argt->type, Arg(fe)))
138 	{
139 	    RaiseStandardException (exception_invalid_argument, 3,
140 				    NewStrString ("Incompatible argument"),
141 				    NewInt (fe), Arg(fe));
142 	    RETURN (Void);
143 	}
144 	fe++;
145 	if (!argt->varargs)
146 	    argt = argt->next;
147     }
148 
149     if (code->base.builtin)
150     {
151 	Value	*values = 0;
152 	int	formal;
153 
154 	formal = code->base.argc;
155 	if (code->base.varargs)
156 	{
157 	    formal = -1;
158 	    values = AllocateTemp (argc * sizeof (Value));
159 	    for (fe = 0; fe < argc; fe++)
160 		values[fe] = Arg(fe);
161 	}
162 
163 	if (code->builtin.needsNext)
164 	{
165 	    /*
166 	     * Let the non-local function handle the stack adjust
167 	     */
168 	    *stack = 0;
169 	    switch (formal) {
170 	    case -1:
171 		value = (*code->builtin.b.builtinNJ)(next, argc, values);
172 		break;
173 	    case 0:
174 		value = (*code->builtin.b.builtin0J)(next);
175 		break;
176 	    case 1:
177 		value = (*code->builtin.b.builtin1J)(next, Arg(0));
178 		break;
179 	    case 2:
180 		value = (*code->builtin.b.builtin2J)(next, Arg(0), Arg(1));
181 		break;
182 	    }
183 	}
184 	else
185 	{
186 	    switch (formal) {
187 	    case -1:
188 		value = (*code->builtin.b.builtinN)(argc, values);
189 		break;
190 	    case 0:
191 		value = (*code->builtin.b.builtin0)();
192 		break;
193 	    case 1:
194 		value = (*code->builtin.b.builtin1)(Arg(0));
195 		break;
196 	    case 2:
197 		value = (*code->builtin.b.builtin2)(Arg(0), Arg(1));
198 		break;
199 	    case 3:
200 		value = (*code->builtin.b.builtin3)(Arg(0), Arg(1), Arg(2));
201 		break;
202 	    case 4:
203 		value = (*code->builtin.b.builtin4)(Arg(0), Arg(1), Arg(2),
204 						    Arg(3));
205 		break;
206 	    case 5:
207 		value = (*code->builtin.b.builtin5)(Arg(0), Arg(1), Arg(2),
208 						    Arg(3), Arg(4));
209 		break;
210 	    case 6:
211 		value = (*code->builtin.b.builtin6)(Arg(0), Arg(1), Arg(2),
212 						    Arg(3), Arg(4), Arg(5));
213 		break;
214 	    case 7:
215 		value = (*code->builtin.b.builtin7)(Arg(0), Arg(1), Arg(2),
216 						    Arg(3), Arg(4), Arg(5),
217 						    Arg(6));
218 		break;
219 	    default:
220 		value = Void;
221 		break;
222 	    }
223 	    /*
224 	     * For a tail call, drop the topmost frame
225 	     */
226 	    if (tail && !aborting)
227 	    {
228 		complete = True;
229 		thread->thread.continuation.obj = thread->thread.continuation.frame->saveObj;
230 		*next = thread->thread.continuation.frame->savePc;
231 		thread->thread.continuation.frame = thread->thread.continuation.frame->previous;
232 	    }
233 	}
234     }
235     else
236     {
237 	frame = BuildFrame (thread, func, value, False, tail, code->base.varargs,
238 			    code->base.argc, base, argc, *next, thread->thread.continuation.obj);
239 	if (aborting)
240 	    RETURN (value);
241 	complete = True;
242 	thread->thread.continuation.frame = frame;
243 	thread->thread.continuation.obj = code->func.body.obj;
244 	*next = ObjCode (code->func.body.obj, 0);
245     }
246     RETURN (value);
247 }
248 
249 /*
250  * Call the pseudo function to initialize static values
251  */
252 static void
ThreadStaticInit(Value thread,InstPtr * next)253 ThreadStaticInit (Value thread, InstPtr *next)
254 {
255     ENTER ();
256     Value	value = thread->thread.continuation.value;
257     CodePtr	code = value->func.code;
258     FramePtr	frame;
259 
260     frame = BuildFrame (thread, value, Void, True, False, False, 0, 0, 0,
261 			*next, thread->thread.continuation.obj);
262     if (aborting)
263 	return;
264     complete = True;
265     thread->thread.continuation.frame = frame;
266     thread->thread.continuation.obj = code->func.staticInit.obj;
267     *next = ObjCode (code->func.staticInit.obj, 0);
268     EXIT ();
269 }
270 
271 static inline void
ThreadAssign(Value ref,Value v,Bool initialize)272 ThreadAssign (Value ref, Value v, Bool initialize)
273 {
274     ENTER ();
275     if (!ValueIsRef (ref))
276 	RaiseStandardException (exception_invalid_binop_values, 2, ref, v);
277     else if (RefConstant(ref) && !initialize)
278 	RaiseStandardException (exception_readonly_box, 1, v);
279     else if (ref->ref.element >= ref->ref.box->nvalues)
280 	RaiseStandardException (exception_invalid_array_bounds, 2,
281 				NewInt(ref->ref.element), v);
282     else if (!TypeCompatibleAssign (RefType (ref), v))
283     {
284 	RaiseStandardException (exception_invalid_argument, 3,
285 				NewStrString ("Incompatible types in assignment"),
286 				NewInt(ref->ref.element), v);
287     }
288     else
289     {
290 	if (!v)
291 	    abort ();
292 	v = Copy (v);
293 	if (!aborting)
294 	{
295 	    complete = True;
296 	    RefValueSet (ref, v);
297 	}
298     }
299     EXIT ();
300 }
301 
302 static Value
ThreadArray(Value thread,Bool resizable,int ndim,Type * type)303 ThreadArray (Value thread, Bool resizable, int ndim, Type *type)
304 {
305     ENTER ();
306     int	    i;
307     int	    *dims;
308 
309     dims = AllocateTemp (ndim * sizeof (int));
310     for (i = 0; i < ndim; i++)
311     {
312 	Value	d = Stack(i);
313 	dims[i] = IntPart (d, "Invalid array dimension");
314 	if (dims[i] < 0)
315 	    RaiseStandardException (exception_invalid_argument, 3,
316 				    NewStrString ("Negative array dimension"),
317 				    NewInt (0), d);
318 	if (aborting)
319 	    RETURN (0);
320     }
321     RETURN (NewArray (False, resizable, type, ndim, dims));
322 }
323 
324 static Value
ThreadArrayInd(Value thread,Bool resizable,Value dim,Type * type)325 ThreadArrayInd (Value thread, Bool resizable, Value dim, Type *type)
326 {
327     ENTER ();
328     Array   *a = &dim->array;
329     int	    i;
330     int	    ndim = ArrayLimits(a)[0];
331     int	    *dims;
332 
333     dims = AllocateTemp (ndim * sizeof (int));
334     for (i = 0; i < ndim; i++)
335     {
336 	Value	d = ArrayValue (a, i);
337 	dims[i] = IntPart (d, "Invalid array dimension");
338 	if (dims[i] < 0)
339 	    RaiseStandardException (exception_invalid_argument, 3,
340 				    NewStrString ("Negative array dimension"),
341 				    NewInt (0), d);
342 	if (aborting)
343 	    RETURN (0);
344     }
345     RETURN (NewArray (False, resizable, type, ndim, dims));
346 }
347 
348 static int
ThreadArrayIndex(Value array,Value thread,int ndim,Value last,int off,Bool except,Bool resize)349 ThreadArrayIndex (Value array, Value thread, int ndim,
350 		  Value last, int off, Bool except, Bool resize)
351 {
352     int	    i;
353     int	    dim;
354     int	    part;
355     Value   d;
356     int	    *dims = ArrayDims (&array->array);
357     int	    *limits = ArrayLimits (&array->array);
358 
359     i = 0;
360     for (dim = ndim - 1; dim >= 0; dim--)
361     {
362 	if (dim == 0)
363 	    d = last;
364 	else
365 	    d = Stack(dim + off - 1);
366 	if (!ValueIsInt(d) || (part = ValueInt(d)) < 0)
367 	{
368 	    RaiseStandardException (exception_invalid_argument, 3,
369 				    NewStrString ("Array index not non-negative integer"),
370 				    array, d);
371 	    return 0;
372 	}
373 	if (limits[dim] <= part)
374 	{
375 	    if (resize && array->array.resizable)
376 	    {
377 		if (dims[dim] > part)
378 		    limits[dim] = part + 1;
379 		else
380 		    ArrayResize (array, dim, part + 1);
381 	    }
382 	    else if (except)
383 	    {
384 		RaiseStandardException (exception_invalid_array_bounds, 2,
385 					array, d);
386 		return 0;
387 	    }
388 	}
389 	i = i * dims[dim] + part;
390     }
391     return i;
392 }
393 
394 /*
395  * Array initialization
396  *
397  * Array initialization uses the stack to hold temporary index values while
398  * the array is walked.  The stack looks like:
399  *
400  *	array
401  *	major-index
402  *	...
403  *	minor-index
404  *	num-dimensions
405  *
406  * Each Element Repeat instruction indicates which dimension
407  * is being stepped over.  When the entire array has been walked,
408  * a final Element inst with ndim set to the dimensionality of the
409  * array is executed which pops the whole mess off the stack and
410  * returns the completed array
411  *
412  * Repeat elements indicate along which dimension the repeat occurs.
413  * The initial value for the repeat has already been stored in the
414  * array, so the task is just to copy that first element to the end
415  * of the dimension.
416  */
417 
418 static void
ThreadArrayReplicate(Value thread,Value array,int dim,int start)419 ThreadArrayReplicate (Value thread, Value array, int dim, int start)
420 {
421     int		dimsize = 1;
422     int		i;
423     int		total;
424     Value	*elements;
425 
426     for (i = 0; i < dim; i++)
427 	dimsize *= ArrayDims(&array->array)[i];
428     start = start - dimsize;
429     total = ArrayDims(&array->array)[dim] * dimsize;
430     if (array->array.resizable) {
431 	for (i = start + dimsize; i % total; i += dimsize) {
432 	    int j;
433 	    for (j = 0; j < dimsize; j++)
434 		ArrayValueSet(&array->array, i + j, ArrayValueGet(&array->array, start + j));
435 	}
436     } else {
437 	elements = BoxElements (array->array.u.fix);
438 	for (i = start + dimsize; i % total; i += dimsize)
439 	    memmove (elements + i, elements + start,
440 		     dimsize * sizeof (elements[0]));
441     }
442 }
443 
444 void
445 ThreadStackDump (Value thread);
446 
447 static Value
ThreadArrayInit(Value thread,Value value,AInitMode mode,int dim,int * stack,InstPtr * next)448 ThreadArrayInit (Value thread, Value value, AInitMode mode,
449 		 int dim, int *stack, InstPtr *next)
450 {
451     ENTER ();
452     Value   array;
453     int	    i;
454     int	    ndim;
455 
456     if (aborting)
457 	RETURN(value);
458     switch (mode) {
459     case AInitModeStart:
460 	complete = True;
461 	STACK_PUSH (thread->thread.continuation.stack, value);
462 	for (i = 0; i < dim; i++)
463 	    STACK_PUSH (thread->thread.continuation.stack, Zero);
464 	STACK_PUSH (thread->thread.continuation.stack, NewInt(dim));
465 	break;
466     case AInitModeRepeat:
467         ndim = ValueInt(Stack(0));
468 	array = Stack(ndim+1);
469 	if (ValueInt(Stack(dim+1)) == ArrayDims(&array->array)[dim])
470 	    break;
471 	/* fall through ... */
472     case AInitModeElement:
473         ndim = ValueInt(Stack(0));
474 	array = Stack(ndim+1);
475 	/*
476 	 * Check and see if we're done
477 	 */
478 	if (dim == ndim)
479 	{
480 	    *stack = ndim + 2;
481 	    value = array;
482 	    break;
483 	}
484 	/*
485 	 * Initialize a single value?
486 	 */
487 	if (dim == 0)
488 	{
489 	    if (!TypeCompatibleAssign (ArrayType(&array->array), value))
490 	    {
491 		RaiseStandardException (exception_invalid_argument, 3,
492 				NewStrString ("Incompatible types in array initialization"),
493 				array, value);
494 		break;
495 	    }
496 	    i = ThreadArrayIndex (array, thread, ndim, Stack(1), 2, True, False);
497 	    if (aborting)
498 		break;
499 	    complete=True;
500 	    ArrayValueSet (&array->array, i, Copy (value));
501 	}
502 	complete = True;
503 	/*
504 	 * Step to the next element
505 	 */
506 	STACK_DROP(thread->thread.continuation.stack, dim+1);
507 	STACK_PUSH(thread->thread.continuation.stack,
508 		   Plus (STACK_POP(thread->thread.continuation.stack),
509 				   One));
510 	/*
511 	 * Reset remaining indices to zero
512 	 */
513 	for (i = 0; i < dim; i++)
514 	    STACK_PUSH (thread->thread.continuation.stack, Zero);
515 	STACK_PUSH (thread->thread.continuation.stack, NewInt (ndim));
516 	if (mode == AInitModeRepeat)
517 	{
518 	    i = ThreadArrayIndex (array, thread, ndim, Stack(1), 2, False, False);
519 	    ThreadArrayReplicate (thread, array, dim, i);
520 	}
521 	break;
522     case AInitModeFunc:
523 	if (aborting)
524 	    break;
525 	complete = True;
526 	/*
527 	 * Fetch the function
528 	 */
529 	value = Stack(dim+2);
530 	/*
531 	 * Push args. Tricky because the stack keeps growing
532 	 */
533 	i = dim + 1;
534 	while (--dim >= 0)
535 	{
536 	    STACK_PUSH(thread->thread.continuation.stack, value);
537 	    value = Stack(i);
538 	}
539 	break;
540     case AInitModeFuncDone:
541         ndim = ValueInt(Stack(0));
542 	value = Stack(ndim+1);
543 	*stack = ndim + 3;
544 	break;
545     case AInitModeTest:
546 	if (aborting)
547 	    break;
548 	complete = True;
549         ndim = ValueInt(Stack(0));
550 	array = Stack(ndim+1);
551 	value = FalseVal;
552 	/* Done with this row? */
553 	if (ValueInt(Stack(1)) == ArrayDims(&array->array)[0])
554 	{
555 	    /* Find dim with space */
556 	    for (dim = 1; dim < ndim; dim++)
557 		if (ValueInt(Stack(1+dim)) < ArrayDims(&array->array)[dim] - 1)
558 		    break;
559 	    /* All done? */
560 	    if (dim == ndim)
561 	    {
562 		value = TrueVal;
563 		break;
564 	    }
565 	    /*
566 	     * Step to the next element
567 	     */
568 	    STACK_DROP(thread->thread.continuation.stack, dim+1);
569 	    STACK_PUSH(thread->thread.continuation.stack,
570 		       Plus (STACK_POP(thread->thread.continuation.stack),
571 			     One));
572 	    /*
573 	     * Reset remaining indices to zero
574 	     */
575 	    while (--dim >= 0)
576 		STACK_PUSH (thread->thread.continuation.stack, Zero);
577 	    STACK_PUSH (thread->thread.continuation.stack, NewInt (ndim));
578 	}
579 	break;
580     }
581     RETURN (value);
582 }
583 
584 
585 #ifdef DEBUG_JUMP
586 void
ThreadCatches(Value thread)587 ThreadCatches (Value thread)
588 {
589     CatchPtr	catch;
590 
591     FilePrintf (FileStdout, "(");
592     for (catch = thread->thread.continuation.catches;
593 	 catch;
594 	 catch = catch->continuation.catches)
595     {
596 	FilePrintf (FileStdout, "%A ", catch->exception->symbol.name);
597     }
598     FilePrintf (FileStdout, ")\n");
599 }
600 #endif
601 
602 static Value
ThreadRaise(Value thread,Value value,int argc,SymbolPtr exception,InstPtr * next)603 ThreadRaise (Value thread, Value value, int argc, SymbolPtr exception, InstPtr *next)
604 {
605     ENTER ();
606     StackObject *cstack = thread->thread.continuation.stack;
607     Value	args;
608     int		i;
609     int		base = argc - 2;
610 
611 #ifdef DEBUG_JUMP
612     FilePrintf (FileStdout, "    Raise: %A ", exception->symbol.name);
613     ThreadCatches (thread);
614 #endif
615     /*
616      * Build and array to hold the arguments, this will end up
617      * in the thread's value on entry to the catch block
618      */
619     args = NewArray (False, False, typePoly, 1, &argc);
620     for (i = 0; i < argc; i++)
621         ArrayValueSet (&args->array, i, Arg(i));
622     if (!aborting)
623     {
624 	RaiseException (thread, exception, args, next);
625 	if (!aborting)
626 	    complete = True;
627     }
628     RETURN (args);
629 }
630 
631 static void
ThreadEndCatch(Value thread,int catches)632 ThreadEndCatch (Value thread, int catches)
633 {
634 #ifdef DEBUG_JUMP
635     FilePrintf (FileStdout, "    EndCatch: %d ", catches);
636 #endif
637     while (catches--)
638         thread->thread.continuation.catches = thread->thread.continuation.catches->continuation.catches;
639 #ifdef DEBUG_JUMP
640     ThreadCatches (thread);
641 #endif
642 }
643 
644 
645 static Value
ThreadExceptionCall(Value thread,InstPtr * next,int * stack)646 ThreadExceptionCall (Value thread, InstPtr *next, int *stack)
647 {
648     ENTER ();
649     Value   args;
650     Value   ret;
651     int	    argc;
652     int	    i;
653 
654     /*
655      * The compiler places a Noop with the push flag set
656      * before the function is stuffed in the thread value,
657      * this pushes the array of arguments carefully crafted
658      * in ThreadRaise above.  Fetch the argument array and
659      * push all of them onto the stack.
660      */
661     args = Stack(0);
662     if (!ValueIsArray (args))
663     {
664 	RaiseStandardException (exception_invalid_argument, 3,
665 				NewStrString ("exception call argument must be array"),
666 				NewInt (0), args);
667 	*stack = 1;
668 	RETURN (Void);
669     }
670     if (aborting)
671     {
672 	*stack = 1;
673 	RETURN (Void);
674     }
675     complete = True;
676     argc = ArrayLimits(&args->array)[0];
677     for (i = 0; i < argc; i++)
678     {
679 	STACK_PUSH (thread->thread.continuation.stack,
680 		    thread->thread.continuation.value);
681 	thread->thread.continuation.value = ArrayValue(&args->array, i);
682     }
683     /*
684      * Call the function
685      */
686     ret = ThreadCall (thread, False, next, &argc);
687     /*
688      * Account for the argument array
689      */
690     *stack = 1 + argc;
691     RETURN (ret);
692 }
693 
694 static void
ThreadFarJump(Value thread,Value ret,FarJumpPtr farJump,InstPtr * next)695 ThreadFarJump (Value thread, Value ret, FarJumpPtr farJump, InstPtr *next)
696 {
697     ENTER ();
698     Value	continuation;
699 
700     /*
701      * Build the continuation
702      */
703     continuation = FarJumpContinuation (&thread->thread.continuation, farJump);
704     /*
705      * And jump
706      */
707     if (!aborting)
708     {
709 	complete = True;
710 	ContinuationJump (thread, &continuation->continuation, ret, next);
711     }
712     EXIT ();
713 }
714 
715 static void
ThreadUnwind(Value thread,int twixt,int catch)716 ThreadUnwind (Value thread, int twixt, int catch)
717 {
718     while (twixt--)
719 	thread->thread.continuation.twixts = thread->thread.continuation.twixts->continuation.twixts;
720 #ifdef DEBUG_JUMP
721     FilePrintf (FileStdout, "     Before unwind: ");
722     ThreadCatches (thread);
723 #endif
724     while (catch--)
725     {
726 #ifdef DEBUG_JUMP
727 	FilePrintf (FileStdout, "    Unwind: %A\n",
728 			thread->thread.continuation.catches->exception->symbol.name);
729 #endif
730 	thread->thread.continuation.catches = thread->thread.continuation.catches->continuation.catches;
731     }
732 #ifdef DEBUG_JUMP
733     FilePrintf (FileStdout, "     After unwind: ");
734     ThreadCatches (thread);
735 #endif
736 }
737 
738 #define ThreadBoxCheck(box,i) (BoxValueGet(box,i) == 0 ? ThreadBoxSetDefault(box,i,0) : 0)
739 
740 typedef struct _TypeChain {
741     struct _TypeChain	*prev;
742     Type   *type;
743 } TypeChain;
744 
745 static void
ThreadBoxSetDefault(BoxPtr box,int i,TypeChain * chain)746 ThreadBoxSetDefault (BoxPtr box, int i, TypeChain *chain)
747 {
748     if (BoxValueGet (box, i) == 0)
749     {
750 	Type	    *ctype = TypeCanon (BoxType (box, i));
751 	StructType  *st = ctype->structs.structs;
752 	TypeChain   link, *c;
753 
754 	/*
755 	 * Check for recursion
756 	 */
757 	for (c = chain; c; c = c->prev)
758 	    if (c->type == ctype)
759 		return;
760 
761 	link.prev = chain;
762 	link.type = ctype;
763 
764 	switch (ctype->base.tag) {
765 	case type_union:
766 	    BoxValueSet (box, i, NewUnion (st, False));
767 	    break;
768 	case type_struct:
769 	    BoxValueSet (box, i, NewStruct (st, False));
770 	    box = BoxValueGet (box, i)->structs.values;
771 	    for (i = 0; i < st->nelements; i++)
772 	    {
773 		if (BoxValueGet (box, i) == 0)
774 		    ThreadBoxSetDefault (box, i, &link);
775 	    }
776 	    break;
777 	default:
778 	    break;
779 	}
780     }
781 }
782 
783 static Value
ThreadOpArray(Value thread,Value value,int stack,Bool fetch,Bool typeCheck)784 ThreadOpArray (Value thread, Value value, int stack, Bool fetch, Bool typeCheck)
785 {
786     Value   v;
787     char    *s;
788     int	    i;
789 
790     v = Stack(stack-1);
791     switch (ValueTag(v)) {
792     case rep_string:
793 	if (!fetch)
794 	{
795 	    RaiseStandardException (exception_invalid_binop_values, 2,
796 				    v, value);
797 	    break;
798 	}
799 	if (stack != 1)
800 	{
801 	    RaiseStandardException (exception_invalid_binop_values, 2,
802 				    NewInt (stack), v);
803 	    break;
804 	}
805 	i = IntPart (value, "Invalid string index");
806 	if (aborting)
807 	    break;
808 	s = StringChars (&v->string);
809 	if (i < 0 || StringLength (s, v->string.length) <= i)
810 	{
811 	    RaiseStandardException (exception_invalid_binop_values, 2,
812 				    v, value);
813 	    break;
814 	}
815 	value = NewInt (StringGet (s, v->string.length, i));
816 	break;
817     case rep_array:
818 	if (stack != v->array.ndim)
819 	{
820 	    RaiseStandardException (exception_invalid_binop_values, 2,
821 				    NewInt (stack), v);
822 	    break;
823 	}
824 	i = ThreadArrayIndex (v, thread, stack, value, 0, True, !fetch);
825 	if (!aborting)
826 	{
827 	    BoxPtr  box = ArrayValueBox (&v->array, i);
828 	    int	    elt = ArrayValueElt (&v->array, i);
829 	    if (typeCheck)
830 		ThreadBoxCheck (box, elt);
831 	    if (fetch)
832 		value = BoxValue (box, elt);
833 	    else
834 		value = NewRef (box, elt);
835 	}
836 	break;
837     case rep_hash:
838 	if (stack != 1)
839 	{
840 	    RaiseStandardException (exception_invalid_binop_values, 2,
841 				    NewInt (stack), v);
842 	    break;
843 	}
844 	if (fetch)
845 	    value = HashGet (v, value);
846 	else
847 	    value = HashRef (v, value);
848 	break;
849     default:
850 	RaiseStandardException (exception_invalid_unop_value, 1, v);
851 	break;
852     }
853     return value;
854 }
855 
856 static Value
ThreadOpDot(Value thread,Value value,Atom atom,Bool fetch)857 ThreadOpDot (Value thread, Value value, Atom atom, Bool fetch)
858 {
859     Value   v;
860 
861     switch (ValueTag(value)) {
862     default:
863 	RaiseStandardException (exception_invalid_unop_value, 1, value);
864 	break;
865     case rep_struct:
866 	if (fetch)
867 	    v = StructMemValue (value, atom);
868 	else
869 	    v = StructMemRef (value, atom);
870 	if (!v)
871 	{
872 	    RaiseStandardException (exception_invalid_struct_member, 2,
873 				    value, NewStrString (AtomName (atom)));
874 	    break;
875 	}
876 	value = v;
877 	break;
878     case rep_union:
879 	if (fetch)
880 	    v = UnionValue (value, atom);
881 	else
882 	    v = UnionRef (value, atom);
883 	if (!v)
884 	{
885 	    if (StructMemType (value->unions.type, atom))
886 		RaiseStandardException (exception_invalid_struct_member, 2,
887 					value, NewStrString (AtomName (atom)));
888 	    else
889 		RaiseStandardException (exception_invalid_struct_member, 2,
890 					value, NewStrString (AtomName (atom)));
891 	    break;
892 	}
893 	value = v;
894 	break;
895     }
896     return value;
897 }
898 
899 #include	<signal.h>
900 
901 void
ThreadStackDump(Value thread)902 ThreadStackDump (Value thread)
903 {
904     StackObject	    *cstack = thread->thread.continuation.stack;
905     StackChunk	    *chunk;
906     StackPointer    stackPointer;
907     int		    i = 0;
908 
909     chunk = cstack->current;
910     stackPointer = STACK_TOP(cstack);
911     while (chunk)
912     {
913 	while (stackPointer < CHUNK_MAX(chunk))
914 	{
915 	    FilePrintf (FileStdout, "%d: %v\n", i++, (Value) *stackPointer++);
916 	}
917 	chunk = chunk->previous;
918 	stackPointer = CHUNK_MIN(chunk);
919     }
920 }
921 
922 #ifdef DEBUG_INST
923 int dump_inst = 0;
924 #endif
925 
926 #ifdef VALIDATE_EXECUTION
927 
928 extern DataType FrameType, BoxType, stackType, stackChunkType, ObjType;
929 
930 static void
ObjValid(ObjPtr obj,InstPtr pc)931 ObjValid(ObjPtr obj, InstPtr pc)
932 {
933     assert(obj->data == &ObjType);
934     assert(0 <= obj->used && obj->used <= obj->size);
935     assert(0 <= obj->used_stat && obj->used_stat <= obj->size_stat);
936     assert(obj->insts <= pc && pc < &obj->insts[obj->used]);
937 }
938 
939 static void
FrameValid(FramePtr frame)940 FrameValid(FramePtr frame)
941 {
942     assert (frame->data == &FrameType);
943 
944     if (frame->previous)
945 	assert (frame->previous->data == &FrameType);
946 
947     if (frame->staticLink)
948 	assert (frame->staticLink->data == &FrameType);
949 
950     assert (ValueIsFunc(frame->function));
951 
952     if (frame->frame)
953 	assert (frame->frame->data == &BoxType);
954     if (frame->statics)
955 	assert (frame->statics->data == &BoxType);
956 
957     ObjValid(frame->saveObj, frame->savePc);
958 }
959 
960 static void
StackValid(StackObject * stack)961 StackValid(StackObject *stack)
962 {
963     StackChunk		*chunk;
964     StackElement	*stackPointer;
965 
966     assert(stack->type == &stackType);
967 
968     chunk = stack->current;
969     if (chunk) {
970 	assert(chunk->type == &stackChunkType);
971 	if (chunk->previous)
972 	    assert (chunk->previous->type == &stackChunkType);
973     }
974 
975     stackPointer = stack->stackPointer;
976     assert ((stackPointer == NULL) == (chunk == NULL));
977     if (stackPointer) {
978 	assert (&chunk->elements[0] <= stackPointer &&
979 		stackPointer <= &chunk->elements[STACK_ENTS_PER_CHUNK]);
980     }
981 }
982 
983 static void
ThreadValid(Value thread)984 ThreadValid(Value thread)
985 {
986     Thread 	*t;
987     FramePtr	frame;
988     StackObject	*stack;
989 
990     assert(thread->value.type == &ThreadRep);
991     t = &thread->thread;
992 
993     /* Check to make sure object is valid */
994     ObjValid(t->continuation.obj,
995 	     t->continuation.pc);
996 
997     /* Check for valid frame */
998     frame = t->continuation.frame;
999     if (frame)
1000 	FrameValid(frame);
1001 
1002     stack = t->continuation.stack;
1003     if (stack)
1004 	StackValid(stack);
1005 }
1006 
1007 #define EXEC_HISTORY	256
1008 Continuation	exec_history[EXEC_HISTORY];
1009 int		exec_history_i;
1010 
1011 static inline void
ExecRecord(Value thread)1012 ExecRecord(Value thread)
1013 {
1014     exec_history[exec_history_i] = thread->thread.continuation;
1015     exec_history_i = (exec_history_i + 1) % EXEC_HISTORY;
1016 }
1017 #else
1018 #define ThreadValid(t)
1019 #define ExecRecord(t)
1020 #endif
1021 
1022 void
ThreadsRun(Value thread,Value lex)1023 ThreadsRun (Value thread, Value lex)
1024 {
1025     signalInterrupt = False;
1026     for (;;)
1027     {
1028 	if (signaling)
1029 	{
1030 	    signaling = False;
1031 	    aborting = False;
1032 	    /*
1033 	     * Check for pending external signals
1034 	     */
1035 	    if (signalInterrupt)
1036 	    {
1037 		signalInterrupt = False;
1038 		ThreadsSignal (NewInt (SIGINT));
1039 	    }
1040 	    if (signalTimer)
1041 	    {
1042 		signalTimer = False;
1043 		TimerInterrupt ();
1044 	    }
1045 	    if (signalIo)
1046 	    {
1047 		signalIo = False;
1048 		IoInterrupt ();
1049 	    }
1050 	    if (signalChild)
1051 	    {
1052 		signalChild = False;
1053 		ProcessInterrupt ();
1054 	    }
1055 	    if (lex && !(lex->file.flags & (FileInputBlocked|FileOutputBlocked)))
1056 		break;
1057 	}
1058 	else if (thread && thread->thread.state == ThreadFinished)
1059 	    break;
1060 	else if (!running)
1061 	{
1062 	    /* when all threads are done, and all input is read, time to go */
1063 	    if (!lex && !stopped)
1064 		break;
1065 	    ThreadsBlock ();
1066 	}
1067 	else
1068 	{
1069 	    ENTER ();
1070 	    Value	thread = running;
1071 	    StackObject	*cstack;
1072 	    InstPtr	inst, next;
1073 	    FramePtr	fp;
1074 	    int		i, j;
1075 	    int		stack;
1076 	    Value	value, v, w;
1077 	    BoxPtr	box;
1078 
1079 	    inst = thread->thread.continuation.pc;
1080 	    value = thread->thread.continuation.value;
1081 	    cstack = thread->thread.continuation.stack;
1082 	    for (j = 0; j < 10; j++)
1083 	    {
1084 		ThreadValid(thread);
1085 		ExecRecord(thread);
1086 		stack = 0;
1087 		next = inst + 1;
1088 		complete = False;
1089 #ifdef DEBUG_INST
1090 		if (dump_inst)
1091 		{
1092 		    InstDump (inst, 1, 0, 0, 0);
1093 		    FileFlush (FileStdout, True);
1094 		}
1095 #endif
1096 		switch (inst->base.opCode) {
1097 		case OpNoop:
1098 		    break;
1099 		case OpBranch:
1100 		    next = inst + inst->branch.offset;
1101 		    break;
1102 		case OpBranchFalse:
1103 		    if (!ValueIsBool(value))
1104 		    {
1105 			RaiseStandardException (exception_invalid_argument, 3,
1106 						NewStrString ("conditional expression not bool"),
1107 						value, Void);
1108 			break;
1109 		    }
1110 		    if (!True (value))
1111 			next = inst + inst->branch.offset;
1112 		    break;
1113 		case OpBranchTrue:
1114 		    if (!ValueIsBool(value))
1115 		    {
1116 			RaiseStandardException (exception_invalid_argument, 3,
1117 						NewStrString ("conditional expression not bool"),
1118 						value, Void);
1119 			break;
1120 		    }
1121 		    if (True (value))
1122 			next = inst + inst->branch.offset;
1123 		    break;
1124 		case OpCase:
1125 		    value = Equal (CStack(stack), value);
1126 		    if (True (value))
1127 		    {
1128 			next = inst + inst->branch.offset;
1129 			stack++;
1130 		    }
1131 		    break;
1132 		case OpDefault:
1133 		    next = inst + inst->branch.offset;
1134 		    stack++;
1135 		    break;
1136 		case OpTagCase:
1137 		    if (!ValueIsUnion(value))
1138 		    {
1139 			RaiseStandardException (exception_invalid_argument, 3,
1140 						NewStrString ("union switch expression not union"),
1141 						value, Void);
1142 			break;
1143 		    }
1144 		    if (value->unions.tag == inst->tagcase.tag)
1145 		    {
1146 			next = inst + inst->tagcase.offset;
1147 			v = UnionValue (value, inst->tagcase.tag);
1148 			if (!v)
1149 			{
1150 			    if (StructMemType (value->unions.type, inst->atom.atom))
1151 				RaiseStandardException (exception_invalid_struct_member, 2,
1152 							value, NewStrString (AtomName (inst->atom.atom)));
1153 			    else
1154 				RaiseStandardException (exception_invalid_struct_member, 2,
1155 							value, NewStrString (AtomName (inst->atom.atom)));
1156 			    break;
1157 			}
1158 			value = v;
1159 		    }
1160 		    break;
1161 		case OpTagGlobal:
1162 		    box = inst->box.box;
1163 		    ThreadAssign (NewRef (inst->box.box, 0), value, True);
1164 		    break;
1165 		case OpTagLocal:
1166 		    box = thread->thread.continuation.frame->frame;
1167 		    i = inst->frame.element;
1168 		    ThreadAssign (NewRef (box, i), value, True);
1169 		    break;
1170 		case OpReturnVoid:
1171 		    value = Void;
1172 		    /* fall through */
1173 		case OpReturn:
1174 		    if (!thread->thread.continuation.frame)
1175 		    {
1176 			RaiseStandardException (exception_invalid_argument, 3,
1177 						NewStrString ("return outside of function"),
1178 						Void, Void);
1179 			break;
1180 		    }
1181 		    if (!TypeCompatibleAssign (thread->thread.continuation.frame->function->func.code->base.type,
1182 					       value))
1183 		    {
1184 			RaiseStandardException (exception_invalid_argument, 3,
1185 						NewStrString ("Incompatible type in return"),
1186 						value, Void);
1187 			break;
1188 		    }
1189 		    if (aborting)
1190 			break;
1191 		    complete = True;
1192 		    next = thread->thread.continuation.frame->savePc;
1193 		    thread->thread.continuation.obj = thread->thread.continuation.frame->saveObj;
1194 		    thread->thread.continuation.frame = thread->thread.continuation.frame->previous;
1195 		    break;
1196 		case OpGlobal:
1197 		    ThreadBoxCheck (inst->box.box, 0);
1198 		    value = BoxValue (inst->box.box, 0);
1199 		    break;
1200 		case OpGlobalRef:
1201 		    ThreadBoxCheck (inst->box.box, 0);
1202 		    /* fall through... */
1203 		case OpGlobalRefStore:
1204 		    value = NewRef (inst->box.box, 0);
1205 		    break;
1206 		case OpStatic:
1207 		case OpStaticRef:
1208 		case OpStaticRefStore:
1209 		    for (i = 0, fp = thread->thread.continuation.frame; i < inst->frame.staticLink; i++)
1210 			fp = fp->staticLink;
1211 		    box = fp->statics;
1212 		    i = inst->frame.element;
1213 		    if (inst->base.opCode != OpStaticRefStore)
1214 			ThreadBoxCheck (box, i);
1215 		    if (inst->base.opCode == OpStatic)
1216 			value = BoxValue (box, i);
1217 		    else
1218 			value = NewRef (box, i);
1219 		    break;
1220 		case OpLocal:
1221 		case OpLocalRef:
1222 		case OpLocalRefStore:
1223 		    for (i = 0, fp = thread->thread.continuation.frame; i < inst->frame.staticLink; i++)
1224 			fp = fp->staticLink;
1225 		    box = fp->frame;
1226 		    i = inst->frame.element;
1227 		    if (inst->base.opCode != OpLocalRefStore)
1228 			ThreadBoxCheck (box, i);
1229 		    if (inst->base.opCode == OpLocal)
1230 			value = BoxValue (box, i);
1231 		    else
1232 			value = NewRef (box, i);
1233 		    break;
1234 		case OpFetch:
1235 		    value = Dereference (value);
1236 		    break;
1237 		case OpConst:
1238 		    value = inst->constant.constant;
1239 		    break;
1240 		case OpBuildArray:
1241 		    stack = inst->array.ndim;
1242 		    value = ThreadArray (thread, inst->array.resizable,
1243 					 stack, inst->array.type);
1244 		    break;
1245 		case OpBuildArrayInd:
1246 		    value = ThreadArrayInd (thread, inst->array.resizable,
1247 					    value, inst->array.type);
1248 		    break;
1249 		case OpInitArray:
1250 		    stack = 0;
1251 		    value = ThreadArrayInit (thread, value, inst->ainit.mode,
1252 					     inst->ainit.dim, &stack, &next);
1253 		    break;
1254 		case OpBuildHash:
1255 		    value = NewHash (False, inst->hash.type->hash.keyType,
1256 				     inst->hash.type->hash.type);
1257 		    break;
1258 		case OpInitHash:
1259 		    w = CStack (1);
1260 		    v = CStack (0);
1261 		    stack = 2;
1262 		    HashSet (w, v, value);
1263 		    value = w;
1264 		    break;
1265 		case OpInitHashDef:
1266 		    v = CStack (0);
1267 		    stack = 1;
1268 		    HashSetDef (v, value);
1269 		    value = v;
1270 		    break;
1271 		case OpBuildStruct:
1272 		    value = NewStruct (inst->structs.structs, False);
1273 		    break;
1274 		case OpInitStruct:
1275 		    w = CStack(0); stack = 1;
1276 		    v = StructMemRef (w, inst->atom.atom);
1277 		    if (!v)
1278 		    {
1279 			RaiseStandardException (exception_invalid_struct_member, 2,
1280 						v, NewStrString (AtomName (inst->atom.atom)));
1281 			break;
1282 		    }
1283 		    ThreadAssign (v, value, True);
1284 		    value = w;
1285 		    break;
1286 		case OpBuildUnion:
1287 		    value = NewUnion (inst->structs.structs, False);
1288 		    break;
1289 		case OpInitUnion:
1290 		    v = UnionRef (value, inst->atom.atom);
1291 		    if (!v)
1292 		    {
1293 			RaiseStandardException (exception_invalid_struct_member, 2,
1294 						value, NewStrString (AtomName (inst->atom.atom)));
1295 			break;
1296 		    }
1297 		    w = CStack(0); stack = 1;
1298 		    ThreadAssign (v, w, True);
1299 		    break;
1300 		case OpArray:
1301 		case OpArrayRef:
1302 		case OpArrayRefStore:
1303 		    stack = inst->ints.value;
1304 		    value = ThreadOpArray (thread, value, stack,
1305 					   inst->base.opCode == OpArray,
1306 					   inst->base.opCode != OpArrayRefStore);
1307 		    break;
1308 		case OpVarActual:
1309 		    if (!ValueIsArray(value))
1310 		    {
1311 			RaiseStandardException (exception_invalid_unop_value, 1,
1312 						value);
1313 			break;
1314 		    }
1315 		    if (value->array.ndim != 1)
1316 		    {
1317 			RaiseStandardException (exception_invalid_unop_value, 1,
1318 						value);
1319 			break;
1320 		    }
1321 		    for (i = 0; i < ArrayLimits(&value->array)[0]; i++)
1322 		    {
1323 			STACK_PUSH (cstack, ArrayValue (&value->array, i));
1324 			if (aborting)
1325 			{
1326 			    STACK_DROP (cstack, i + 1);
1327 			    break;
1328 			}
1329 		    }
1330 		    if (i != ArrayLimits(&value->array)[0])
1331 			break;
1332 		    complete = True;
1333 		    value = NewInt (ArrayLimits(&value->array)[0]);
1334 		    break;
1335 		case OpCall:
1336 		case OpTailCall:
1337 		    stack = inst->ints.value;
1338 		    value = ThreadCall (thread, inst->base.opCode == OpTailCall,
1339 					&next, &stack);
1340 		    break;
1341 		case OpArrow:
1342 		case OpArrowRef:
1343 		case OpArrowRefStore:
1344 		    if (!ValueIsRef(value))
1345 		    {
1346 			RaiseStandardException (exception_invalid_unop_value, 1,
1347 						value);
1348 			break;
1349 		    }
1350 		    value = RefValueGet(value);
1351 		    /* fall through ... */
1352 		case OpDot:
1353 		case OpDotRef:
1354 		case OpDotRefStore:
1355 		    value = ThreadOpDot (thread, value, inst->atom.atom,
1356 					 inst->base.opCode == OpArrow || inst->base.opCode == OpDot);
1357 		    break;
1358 		case OpObj:
1359 		    value = NewFunc (inst->code.code, thread->thread.continuation.frame);
1360 		    break;
1361 		case OpStaticInit:
1362 		    /* Always follows OpObj so the function is sitting in value */
1363 		    ThreadStaticInit (thread, &next);
1364 		    break;
1365 		case OpStaticDone:
1366 		    if (!thread->thread.continuation.frame)
1367 		    {
1368 			RaiseStandardException (exception_invalid_argument, 3,
1369 						NewStrString ("StaticInitDone outside of function"),
1370 						Void, Void);
1371 			break;
1372 		    }
1373 		    if (aborting)
1374 			break;
1375 		    complete = True;
1376 		    next = thread->thread.continuation.frame->savePc;
1377 		    thread->thread.continuation.obj = thread->thread.continuation.frame->saveObj;
1378 		    thread->thread.continuation.frame = thread->thread.continuation.frame->previous;
1379 		    /* Fetch the Obj from the stack */
1380 		    value = CStack (0); stack = 1;
1381 		    break;
1382 		case OpBinOp:
1383 		    value = BinaryOperate (CStack(0), value, inst->binop.op); stack = 1;
1384 		    break;
1385 		case OpBinFunc:
1386 		    value = (*inst->binfunc.func) (CStack(0), value); stack = 1;
1387 		    break;
1388 		case OpUnOp:
1389 		    value = UnaryOperate (value, inst->unop.op);
1390 		    break;
1391 		case OpUnFunc:
1392 		    value = (*inst->unfunc.func) (value);
1393 		    break;
1394 		case OpPreOp:
1395 		    v = Dereference (value);
1396 		    if (aborting)
1397 			    break;
1398 		    v = ValueIncDec (v, inst->binop.op);
1399 		    ThreadAssign (value, v, False);
1400 		    value = v;
1401 		    break;
1402 		case OpPostOp:
1403 		    v = Dereference (value);
1404 		    if (aborting)
1405 			    break;
1406 		    ThreadAssign (value, ValueIncDec (v, inst->binop.op), False);
1407 		    value = v;
1408 		    break;
1409 		case OpAssign:
1410 		    ThreadAssign (CStack(0), value, inst->assign.initialize); stack = 1;
1411 		    break;
1412 		case OpAssignOp:
1413 		    v = BinaryOperate (CStack(0), value, inst->binop.op);
1414 		    ThreadAssign (CStack(1), v, False); stack = 2;
1415 		    value = v;
1416 		    break;
1417 		case OpAssignFunc:
1418 		    v = (*inst->binfunc.func) (CStack(0), value);
1419 		    ThreadAssign (CStack(1), v, False); stack = 2;
1420 		    value = v;
1421 		    break;
1422 		case OpFork:
1423 		    value = NewThread (thread->thread.continuation.frame, inst->obj.obj);
1424 		    break;
1425 		case OpCatch:
1426 		    if (aborting)
1427 			break;
1428 #ifdef DEBUG_JUMP
1429 		    FilePrintf (FileStdout, "    Catch: %A ",
1430 				inst->catch.exception->symbol.name);
1431 		    ThreadCatches (thread);
1432 #endif
1433 		    thread->thread.continuation.catches = NewCatch (thread,
1434 								    inst->catch.exception);
1435 		    complete = True;
1436 		    next = inst + inst->catch.offset;
1437 		    break;
1438 		case OpEndCatch:
1439 		    if (aborting)
1440 			break;
1441 		    ThreadEndCatch (thread, inst->ints.value);
1442 		    complete = True;
1443 		    break;
1444 		case OpRaise:
1445 		    if (aborting)
1446 			break;
1447 		    value = ThreadRaise (thread, value, inst->raise.argc, inst->raise.exception, &next);
1448 		    break;
1449 		case OpExceptionCall:
1450 		    ThreadExceptionCall (thread, &next, &stack);
1451 		    break;
1452 		case OpTwixt:
1453 		    if (aborting)
1454 			break;
1455 		    thread->thread.continuation.twixts = NewTwixt (&thread->thread.continuation,
1456 								   inst + inst->twixt.enter,
1457 								   inst + inst->twixt.leave);
1458 		    complete = True;
1459 		    break;
1460 		case OpTwixtDone:
1461 		    if (aborting)
1462 			break;
1463 		    thread->thread.continuation.twixts = thread->thread.continuation.twixts->continuation.twixts;
1464 		    complete = True;
1465 		    break;
1466 		case OpEnterDone:
1467 		    if (thread->thread.jump)
1468 		    {
1469 			if (aborting)
1470 			    break;
1471 			value = JumpContinue (thread, &next);
1472 			if (next)
1473 			    complete = True;
1474 		    }
1475 		    break;
1476 		case OpLeaveDone:
1477 		    if (thread->thread.jump)
1478 		    {
1479 			if (aborting)
1480 			    break;
1481 			value = JumpContinue (thread, &next);
1482 			if (next)
1483 			    complete = True;
1484 		    }
1485 		    break;
1486 		case OpFarJump:
1487 		    ThreadFarJump (thread, value, inst->farJump.farJump, &next);
1488 		    break;
1489 		case OpUnwind:
1490 		    ThreadUnwind (thread, inst->unwind.twixt, inst->unwind.catch);
1491 		    break;
1492 		case OpIsType:
1493 		    value = ValueIsType(value, inst->isType.type) ? TrueVal : FalseVal;
1494 		    break;
1495 		case OpHasMember:
1496 		    if (ValueTag(value) != rep_struct)
1497 			value = FalseVal;
1498 		    else {
1499 			if (StructMemType(value->structs.type, inst->atom.atom))
1500 			    value = TrueVal;
1501 			else
1502 			    value = FalseVal;
1503 		    }
1504 		    break;
1505 		case OpEnd:
1506 		    SetSignalFinished ();
1507 		    break;
1508 		case OpDrop:
1509 		    stack = 1;
1510 		    break;
1511 		default:
1512 		    break;
1513 		}
1514 #if 0
1515 		assert (!next ||
1516 			(ObjCode (thread->thread.continuation.obj, 0) <= next &&
1517 			 next <= ObjCode (thread->thread.continuation.obj,
1518 					  thread->thread.continuation.obj->used)));
1519 #endif
1520 		if (aborting && !complete)
1521 		{
1522 		    /*
1523 		     * Check for pending execution signals
1524 		     */
1525 		    if (signalSuspend)
1526 		    {
1527 			signalSuspend = False;
1528 			if (thread->thread.state == ThreadRunning)
1529 			    ThreadSetState (thread, ThreadSuspended);
1530 		    }
1531 		    if (signalFinished)
1532 		    {
1533 			signalFinished = False;
1534 			ThreadFinish (thread, False);
1535 		    }
1536 		    if (signalException)
1537 		    {
1538 			signalException = False;
1539 			thread->thread.continuation.value = JumpStandardException (thread, &next);
1540 			thread->thread.continuation.pc = next;
1541 		    }
1542 		    if (signalError)
1543 		    {
1544 			signalError = False;
1545 		    }
1546 		    if (signalProfile)
1547 			signalProfile = False;
1548 		    break;
1549 		}
1550 		/* have to do this before the pc is updated */
1551 		if (signalProfile)
1552 		{
1553 		    signalProfile = False;
1554 		    ProfileInterrupt (running);
1555 		}
1556 		/* this instruction has been completely executed */
1557 		thread->thread.partial = 0;
1558 		thread->thread.continuation.value = value;
1559 		cstack = thread->thread.continuation.stack;
1560 		if (stack)
1561 		    STACK_DROP (cstack, stack);
1562 		if (inst->base.flags & InstPush)
1563 		    STACK_PUSH (cstack, value);
1564 		inst = next;
1565 		thread->thread.continuation.pc = inst;
1566 		if (thread->thread.next)
1567 		    ThreadStepped (thread);
1568 		ThreadValid(thread);
1569 		if (running != thread)
1570 		    break;
1571 	    }
1572 	    EXIT ();
1573 	}
1574     }
1575 }
1576