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