1/*
2    Title:  An interpreter for a compact instruction set.
3    Author:     Dave Matthews, Cambridge University Computer Laboratory
4
5    Copyright (c) 2000-7
6        Cambridge University Technical Services Limited
7    Further development Copyright David C.J. Matthews 2015-17.
8
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License version 2.1 as published by the Free Software Foundation.
12
13    This library 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 GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with this library; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22*/
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#elif defined(_WIN32)
27#include "winconfig.h"
28#else
29#error "No configuration file"
30#endif
31
32#ifdef HAVE_STDIO_H
33#include <stdio.h>
34#endif
35
36#ifdef HAVE_ASSERT_H
37#include <assert.h>
38#define ASSERT(x) assert(x)
39#else
40#define ASSERT(x) 0
41#endif
42
43#ifdef HAVE_STRING_H
44#include <string.h>
45#endif
46
47#ifdef HAVE_FLOAT_H
48#include <float.h>
49#endif
50
51#ifdef HAVE_MATH_H
52#include <math.h>
53#endif
54
55#include "globals.h"
56#include "int_opcodes.h"
57#include "machine_dep.h"
58#include "sys.h"
59#include "profiling.h"
60#include "arb.h"
61#include "processes.h"
62#include "run_time.h"
63#include "mpoly.h"
64#include "gc.h"
65#include "basicio.h"
66#include "timing.h"
67#include "arb.h"
68#include "reals.h"
69#include "objsize.h"
70#include "xwindows.h"
71#include "process_env.h"
72#include "network.h"
73#include "basicio.h"
74#include "sighandler.h"
75#include "os_specific.h"
76#include "diagnostics.h"
77#include "polystring.h"
78#include "save_vec.h"
79#include "memmgr.h"
80#include "poly_specific.h"
81#include "scanaddrs.h"
82#include "polyffi.h"
83#include "rtsentry.h"
84
85#define arg1    (pc[0] + pc[1]*256)
86#define arg2    (pc[2] + pc[3]*256)
87#define arg3    (pc[4] + pc[5]*256)
88#define arg4    (pc[6] + pc[7]*256)
89
90const PolyWord True = TAGGED(1);
91const PolyWord False = TAGGED(0);
92const PolyWord Zero = TAGGED(0);
93
94#define CHECKED_REGS 2
95#define UNCHECKED_REGS 0
96
97#define EXTRA_STACK 0 // Don't need any extra - signals aren't handled on the Poly stack.
98
99/* the amount of ML stack space to reserve for registers,
100   C exception handling etc. The compiler requires us to
101   reserve 2 stack-frames worth (2 * 20 words) plus whatever
102   we require for the register save area. We actually reserve
103   slightly more than this. SPF 3/3/97
104*/
105#define OVERFLOW_STACK_SIZE \
106  (50 + \
107   CHECKED_REGS + \
108   UNCHECKED_REGS + \
109   EXTRA_STACK)
110
111
112// This duplicates some code in reals.cpp but is now updated.
113#define DOUBLESIZE (sizeof(double)/sizeof(POLYUNSIGNED))
114
115union realdb { double dble; POLYUNSIGNED puns[DOUBLESIZE]; };
116
117class IntTaskData: public TaskData {
118public:
119    IntTaskData(): interrupt_requested(false), overflowPacket(0), dividePacket(0) {}
120
121    virtual void GarbageCollect(ScanAddress *process);
122    void ScanStackAddress(ScanAddress *process, PolyWord &val, StackSpace *stack);
123    virtual Handle EnterPolyCode(); // Start running ML
124
125    // Switch to Poly and return with the io function to call.
126    int SwitchToPoly();
127    virtual void SetException(poly_exn *exc);
128    virtual void InterruptCode();
129
130    // AddTimeProfileCount is used in time profiling.
131    virtual bool AddTimeProfileCount(SIGNALCONTEXT *context);
132
133    virtual void InitStackFrame(TaskData *newTask, Handle proc, Handle arg);
134
135    // These aren't implemented in the interpreted version.
136    virtual Handle EnterCallbackFunction(Handle func, Handle args) { ASSERT(0); return 0; }
137
138    // Increment or decrement the first word of the object pointed to by the
139    // mutex argument and return the new value.
140    virtual Handle AtomicIncrement(Handle mutexp);
141    // Set a mutex to one.
142    virtual void AtomicReset(Handle mutexp);
143
144    // Return the minimum space occupied by the stack.   Used when setting a limit.
145    virtual POLYUNSIGNED currentStackSpace(void) const { return (this->stack->top - this->taskSp) + OVERFLOW_STACK_SIZE; }
146
147    virtual void addProfileCount(POLYUNSIGNED words) { add_count(this, taskPc, words); }
148
149    virtual void CopyStackFrame(StackObject *old_stack, POLYUNSIGNED old_length, StackObject *new_stack, POLYUNSIGNED new_length);
150
151    bool interrupt_requested;
152
153    // Allocate memory on the heap.  Returns with the address of the cell. Does not set the
154    // length word or any of the data.
155    PolyObject *allocateMemory(POLYUNSIGNED words, POLYCODEPTR &pc, PolyWord *&sp)
156    {
157        words++; // Add the size of the length word.
158        // N.B. The allocation area may be empty so that both of these are zero.
159        if (this->allocPointer >= this->allocLimit + words)
160        {
161            this->allocPointer -= words;
162            return (PolyObject *)(this->allocPointer+1);
163        }
164        // Insufficient space.
165        SaveInterpreterState(pc, sp);
166        // Find some space to allocate in. Returns a pointer to the newly allocated space.
167        // N.B. This may return zero if the heap is exhausted and it has set this
168        // up for an exception.  Generally it allocates by decrementing allocPointer
169        // but if the required memory is large it may allocate in a separate area.
170        PolyWord *space = processes->FindAllocationSpace(this, words, true);
171        LoadInterpreterState(pc, sp);
172        if (space == 0) return 0;
173        return (PolyObject *)(space+1);
174    }
175
176    // Put a real result in a "box"
177    PolyObject *boxDouble(double d, POLYCODEPTR &pc, PolyWord *&sp)
178    {
179        PolyObject *mem = this->allocateMemory(DOUBLESIZE, pc, sp);
180        if (mem == 0) return 0;
181        mem->SetLengthWord(DOUBLESIZE, F_BYTE_OBJ);
182        union realdb uniondb;
183        uniondb.dble = d;
184        // Copy the words.  Depending on the word length this may copy one or more words.
185        for (unsigned i = 0; i < DOUBLESIZE; i++)
186            mem->Set(i, PolyWord::FromUnsigned(uniondb.puns[i]));
187        return mem;
188    }
189
190    // Extract a double value from a box.
191    double unboxDouble(PolyWord p)
192    {
193        union realdb uniondb;
194        for (unsigned i = 0; i < DOUBLESIZE; i++)
195            uniondb.puns[i] = p.AsObjPtr()->Get(i).AsUnsigned();
196        return uniondb.dble;
197    }
198
199    // Update the copies in the task object
200    void SaveInterpreterState(POLYCODEPTR pc, PolyWord *sp)
201    {
202        taskPc = pc;
203        taskSp = sp;
204    }
205
206    // Update the local state
207    void LoadInterpreterState(POLYCODEPTR &pc, PolyWord *&sp)
208    {
209        pc = taskPc;
210        sp = taskSp;
211    }
212
213    POLYCODEPTR     taskPc; /* Program counter. */
214    PolyWord        *taskSp; /* Stack pointer. */
215    PolyWord        *hr;
216    PolyWord        exception_arg;
217    bool            raiseException;
218    PolyWord        *sl; /* Stack limit register. */
219
220    PolyObject      *overflowPacket, *dividePacket;
221};
222
223// This lock is used to synchronise all atomic operations.
224// It is not needed in the X86 version because that can use a global
225// memory lock.
226static PLock mutexLock;
227
228// Special value for return address.
229#define SPECIAL_PC_END_THREAD           TAGGED(1)
230
231class Interpreter : public MachineDependent {
232public:
233    Interpreter() {}
234
235    // Create a task data object.
236    virtual TaskData *CreateTaskData(void) { return new IntTaskData(); }
237    virtual Architectures MachineArchitecture(void) { return MA_Interpreted; }
238};
239
240void IntTaskData::InitStackFrame(TaskData *parentTask, Handle proc, Handle arg)
241/* Initialise stack frame. */
242{
243    StackSpace *space = this->stack;
244    StackObject *stack = (StackObject *)space->stack();
245    PolyObject *closure = DEREFWORDHANDLE(proc);
246    POLYUNSIGNED stack_size = space->spaceSize();
247    this->taskPc = *(byte**)(closure);
248//    this->taskSp = (PolyWord*)stack + stack_size-3; /* sp */
249    this->exception_arg = TAGGED(0); /* Used for exception argument. */
250    this->taskSp = (PolyWord*)stack + stack_size;
251    this->raiseException = false;
252
253    /* Set up exception handler */
254    /* No previous handler so point it at itself. */
255    this->taskSp--;
256    *(this->taskSp) = PolyWord::FromStackAddr(this->taskSp);
257    *(--this->taskSp) = SPECIAL_PC_END_THREAD; /* Default return address. */
258    this->hr = this->taskSp;
259
260    /* If this function takes an argument store it on the stack. */
261    if (arg != 0) *(--this->taskSp) = DEREFWORD(arg);
262
263    *(--this->taskSp) = SPECIAL_PC_END_THREAD; /* Return address. */
264    *(--this->taskSp) = closure; /* Closure address */
265
266    // Make packets for exceptions.
267    overflowPacket = makeExceptionPacket(parentTask, EXC_overflow);
268    dividePacket = makeExceptionPacket(parentTask, EXC_divide);
269}
270
271extern "C" {
272    typedef POLYUNSIGNED(*callFastRts0)();
273    typedef POLYUNSIGNED(*callFastRts1)(PolyWord);
274    typedef POLYUNSIGNED(*callFastRts2)(PolyWord, PolyWord);
275    typedef POLYUNSIGNED(*callFastRts3)(PolyWord, PolyWord, PolyWord);
276    typedef POLYUNSIGNED(*callFastRts4)(PolyWord, PolyWord, PolyWord, PolyWord);
277    typedef POLYUNSIGNED(*callFastRts5)(PolyWord, PolyWord, PolyWord, PolyWord, PolyWord);
278    typedef POLYUNSIGNED(*callFullRts0)(PolyObject *);
279    typedef POLYUNSIGNED(*callFullRts1)(PolyObject *, PolyWord);
280    typedef POLYUNSIGNED(*callFullRts2)(PolyObject *, PolyWord, PolyWord);
281    typedef POLYUNSIGNED(*callFullRts3)(PolyObject *, PolyWord, PolyWord, PolyWord);
282    typedef double (*callRTSFtoF) (double);
283    typedef double (*callRTSGtoF) (PolyWord);
284}
285
286void IntTaskData::InterruptCode()
287/* Stop the Poly code at a suitable place. */
288/* We may get an asynchronous interrupt at any time. */
289{
290    IntTaskData *itd = (IntTaskData *)this;
291    itd->interrupt_requested = true;
292}
293
294
295void IntTaskData::SetException(poly_exn *exc)
296/* Set up the stack of a process to raise an exception. */
297{
298    this->raiseException = true;
299    *(--this->taskSp) = (PolyWord)exc; /* push exception data */
300}
301
302int IntTaskData::SwitchToPoly()
303/* (Re)-enter the Poly code from C. */
304{
305    // These are temporary values used where one instruction jumps to
306    // common code.
307    POLYUNSIGNED    tailCount;
308    PolyWord        *tailPtr;
309    POLYUNSIGNED    returnCount;
310    POLYUNSIGNED    storeWords;
311    POLYUNSIGNED    stackCheck;
312    // Local values.  These are copies of member variables but are used so frequently that
313    // it is important that access should be fast.
314    POLYCODEPTR     pc;
315    PolyWord        *sp;
316
317    LoadInterpreterState(pc, sp);
318
319    sl = (PolyWord*)this->stack->stack()+OVERFLOW_STACK_SIZE;
320
321    // We may have taken an interrupt which has set an exception.
322    if (this->raiseException) goto RAISE_EXCEPTION;
323
324    for(;;){ /* Each instruction */
325        switch(*pc++) {
326
327        case INSTR_enter_int: pc++; /* Skip the argument. */ break;
328
329        case INSTR_jump8false:
330            {
331                PolyWord u = *sp++; /* Pop argument */
332                if (u == True) { pc += 1; break; }
333                /* else - false - take the jump */
334            }
335
336        case INSTR_jump8: pc += *pc + 1; break;
337
338        case INSTR_jump16false:
339        {
340            PolyWord u = *sp++; /* Pop argument */
341            if (u == True) { pc += 2; break; }
342            /* else - false - take the jump */
343        }
344
345        case INSTR_jump16:
346            pc += arg1 + 2; break;
347
348        case INSTR_jump32False:
349        {
350            PolyWord u = *sp++; /* Pop argument */
351            if (u == True) { pc += 4; break; }
352            /* else - false - take the jump */
353        }
354
355        case INSTR_jump32:
356        {
357            // This is a 32-bit signed quantity on both 64-bits and 32-bits.
358            POLYSIGNED offset = pc[3] & 0x80 ? -1 : 0;
359            offset = (offset << 8) | pc[3];
360            offset = (offset << 8) | pc[2];
361            offset = (offset << 8) | pc[1];
362            offset = (offset << 8) | pc[0];
363            pc += offset + 4;
364            break;
365        }
366
367        case INSTR_push_handler: /* Save the old handler value. */
368            *(--sp) = PolyWord::FromStackAddr(this->hr); /* Push old handler */
369            break;
370
371        case INSTR_setHandler8: /* Set up a handler */
372            *(--sp) = PolyWord::FromCodePtr(pc + *pc + 1); /* Address of handler */
373            this->hr = sp;
374            pc += 1;
375            break;
376
377        case INSTR_setHandler16: /* Set up a handler */
378            *(--sp) = PolyWord::FromCodePtr(pc + arg1 + 2); /* Address of handler */
379            this->hr = sp;
380            pc += 2;
381            break;
382
383        case INSTR_setHandler32: /* Set up a handler */
384        {
385            POLYUNSIGNED offset = pc[0] + (pc[1] << 8) + (pc[2] << 16) + (pc[3] << 24);
386            *(--sp) = PolyWord::FromCodePtr(pc + offset + 4); /* Address of handler */
387            this->hr = sp;
388            pc += 4;
389            break;
390        }
391
392        case INSTR_del_handler: /* Delete handler retaining the result. */
393            {
394                PolyWord u = *sp++;
395                sp = this->hr;
396                if (*sp == TAGGED(0)) sp++; // Legacy
397                sp++; // Skip handler entry point
398                // Restore old handler
399                this->hr = (*sp).AsStackAddr();
400                *sp = u; // Put back the result
401                pc += *pc + 1; /* Skip the handler */
402                break;
403            }
404
405        case INSTR_deleteHandler: /* Delete handler retaining the result. */
406        {
407            PolyWord u = *sp++;
408            sp = this->hr;
409            sp++; // Remove handler entry point
410            this->hr = (*sp).AsStackAddr(); // Restore old handler
411            *sp = u; // Put back the result
412            break;
413        }
414
415        case INSTR_jump_i_false:
416            if (*sp++ == True) { pc += 1; break; }
417            /* else - false - take the jump */
418
419        case INSTR_jump_i_u: /* Indirect jump */
420            {
421                // This is always a forward jump
422                pc += *pc + 1;
423                pc += arg1 + 2;
424                break;
425            }
426
427        case INSTR_set_handler_new_i: /* Set up a handler */
428            {
429                byte *u = pc + *pc + 1;
430                *(--sp) = /* Address of handler */
431                    PolyWord::FromCodePtr(u + u[0] + u[1]*256 + 2);
432                this->hr = sp;
433                pc += 1;
434                break;
435            }
436
437        case INSTR_del_handler_i: /* Delete handler retaining the result. */
438            {
439                PolyWord u = *sp++;
440                PolyWord *t;
441                sp = this->hr;
442                PolyWord *endStack = this->stack->top;
443                while((t = (*sp).AsStackAddr()) < sp || t > endStack) sp++;
444                this->hr = t;
445                *sp = u;
446                pc += *pc + 1; /* Skip the handler */
447                pc += arg1 + 2;
448                break;
449            }
450
451        case INSTR_case16:
452            {
453                // arg1 is the largest value that is in the range
454                POLYSIGNED u = UNTAGGED(*sp++); /* Get the value */
455                if (u > arg1 || u < 0) pc += (arg1+2)*2; /* Out of range */
456                else {
457                    pc += 2;
458                    pc += /* Index */pc[u*2]+pc[u*2 + 1]*256; }
459                break;
460            }
461
462        case INSTR_case32:
463        {
464            // arg1 is the number of cases i.e. one more than the largest value
465            // This is followed by that number of 32-bit offsets.
466            // If the value is out of range the default case is immediately after the table.
467            POLYSIGNED u = UNTAGGED(*sp++); /* Get the value */
468            if (u >= arg1 || u < 0) pc += 2 + arg1 * 4; /* Out of range */
469            else
470            {
471                pc += 2;
472                pc += /* Index */pc[u*4] + (pc[u*4+1] << 8) + (pc[u*4+2] << 16) + (pc[u*4+3] << 24);
473            }
474            break;
475        }
476
477        case INSTR_tail_3_b:
478           tailCount = 3;
479           tailPtr = sp + tailCount;
480           sp = tailPtr + *pc;
481           goto TAIL_CALL;
482
483        case INSTR_tail_3_2:
484           tailCount = 3;
485           tailPtr = sp + tailCount;
486           sp = tailPtr + 2;
487           goto TAIL_CALL;
488
489        case INSTR_tail_3_3:
490           tailCount = 3;
491           tailPtr = sp + tailCount;
492           sp = tailPtr + 3;
493           goto TAIL_CALL;
494
495        case INSTR_tail_4_b:
496           tailCount = 4;
497           tailPtr = sp + tailCount;
498           sp = tailPtr + *pc;
499           goto TAIL_CALL;
500
501        case INSTR_tail_b_b:
502           tailCount = *pc;
503           tailPtr = sp + tailCount;
504           sp = tailPtr + pc[1];
505           goto TAIL_CALL;
506
507        case INSTR_tail:
508           /* Tail recursive call. */
509           /* Move items up the stack. */
510           /* There may be an overlap if the function we are calling
511              has more args than this one. */
512           tailCount = arg1;
513           tailPtr = sp + tailCount;
514           sp = tailPtr + arg2;
515           TAIL_CALL: /* For general case. */
516           if (tailCount < 2) Crash("Invalid argument\n");
517           for (; tailCount > 0; tailCount--) *(--sp) = *(--tailPtr);
518           pc = (*sp++).AsCodePtr(); /* Pop the original return address. */
519           /* And drop through. */
520
521        case INSTR_call_closure: /* Closure call. */
522        {
523            PolyWord *t = (*sp).AsStackAddr(); /* Closure */
524            PolyWord u = *t;   /* Get code address. (1st word of closure) */
525            sp--;
526            *sp = sp[1];      /* Move closure up. */
527            sp[1] = PolyWord::FromCodePtr(pc); /* Save return address. */
528            pc = u.AsCodePtr();    /* Get entry point. */
529            this->taskPc = pc; // Update in case we're profiling
530            // Legacy: Check for stack overflow.  This is needed because
531            // old code does not have stack check instructions.
532            if (sp < sl)
533            {
534                POLYUNSIGNED min_size = this->stack->top - sp + OVERFLOW_STACK_SIZE;
535                SaveInterpreterState(pc, sp);
536                CheckAndGrowStack(this, min_size);
537                LoadInterpreterState(pc, sp);
538                sl = (PolyWord*)this->stack->stack() + OVERFLOW_STACK_SIZE;
539            }
540            if (this->interrupt_requested)
541            {
542                // Check for interrupts
543                this->interrupt_requested = false;
544                SaveInterpreterState(pc, sp);
545                return -1;
546            }
547            break;
548        }
549
550        case INSTR_return_w:
551            returnCount = arg1; /* Get no. of args to remove. */
552
553            RETURN: /* Common code for return. */
554            {
555                PolyWord result = *sp++; /* Result */
556                sp++; /* Remove the link/closure */
557                pc = (*sp++).AsCodePtr(); /* Return address */
558                sp += returnCount; /* Add on number of args. */
559                if (pc == (SPECIAL_PC_END_THREAD).AsCodePtr())
560                    exitThread(this); // This thread is exiting.
561                *(--sp) = result; /* Result */
562                this->taskPc = pc; // Update in case we're profiling
563            }
564            break;
565
566        case INSTR_return_b: returnCount = *pc; goto RETURN;
567        case INSTR_return_0: returnCount = 0; goto RETURN;
568        case INSTR_return_1: returnCount = 1; goto RETURN;
569        case INSTR_return_2: returnCount = 2; goto RETURN;
570        case INSTR_return_3: returnCount = 3; goto RETURN;
571
572        case INSTR_stackSize8:
573            stackCheck = *pc++;
574            goto STACKCHECK;
575
576        case INSTR_stackSize16:
577        {
578            stackCheck = arg1; pc += 2;
579        STACKCHECK:
580            // Check there is space on the stack
581            if (sp - stackCheck < sl)
582            {
583                POLYUNSIGNED min_size = this->stack->top - sp + OVERFLOW_STACK_SIZE + stackCheck;
584                SaveInterpreterState(pc, sp);
585                CheckAndGrowStack(this, min_size);
586                LoadInterpreterState(pc, sp);
587                sl = (PolyWord*)this->stack->stack() + OVERFLOW_STACK_SIZE;
588            }
589            // Also check for interrupts
590            if (this->interrupt_requested)
591            {
592                // Check for interrupts
593                this->interrupt_requested = false;
594                SaveInterpreterState(pc, sp);
595                return -1;
596            }
597            break;
598        }
599
600        case INSTR_pad: /* No-op */ break;
601
602        case INSTR_raise_ex:
603            {
604                RAISE_EXCEPTION:
605                this->raiseException = false;
606                PolyException *exn = (PolyException*)((*sp).AsObjPtr());
607                this->exception_arg = exn; /* Get exception data */
608                sp = this->hr;
609                if (*sp == SPECIAL_PC_END_THREAD)
610                    exitThread(this);  // Default handler for thread.
611                pc = (*sp++).AsCodePtr();
612                this->hr = (*sp++).AsStackAddr();
613                break;
614            }
615
616        case INSTR_get_store_w:
617        // Get_store is now only used for mutually recursive closures.  It allocates mutable store
618        // initialised to zero.
619        {
620            storeWords = arg1;
621            pc += 2;
622            GET_STORE:
623            PolyObject *p = this->allocateMemory(storeWords, pc, sp);
624            if (p == 0) goto RAISE_EXCEPTION;
625            p->SetLengthWord(storeWords, F_MUTABLE_BIT);
626            for(; storeWords > 0; ) p->Set(--storeWords, TAGGED(0)); /* Must initialise store! */
627            *(--sp) = p;
628            break;
629        }
630
631        case INSTR_get_store_2: storeWords = 2; goto GET_STORE;
632        case INSTR_get_store_3: storeWords = 3; goto GET_STORE;
633        case INSTR_get_store_4: storeWords = 4; goto GET_STORE;
634        case INSTR_get_store_b: storeWords = *pc; pc++; goto GET_STORE;
635
636        case INSTR_tuple_w:
637        {
638            storeWords = arg1; pc += 2;
639        TUPLE: /* Common code for tupling. */
640            PolyObject *p = this->allocateMemory(storeWords, pc, sp);
641            if (p == 0) goto RAISE_EXCEPTION; // Exception
642            p->SetLengthWord(storeWords, 0);
643            for(; storeWords > 0; ) p->Set(--storeWords, *sp++);
644            *(--sp) = p;
645            break;
646        }
647
648        case INSTR_tuple_2: storeWords = 2; goto TUPLE;
649        case INSTR_tuple_3: storeWords = 3; goto TUPLE;
650        case INSTR_tuple_4: storeWords = 4; goto TUPLE;
651        case INSTR_tuple_b: storeWords = *pc; pc++; goto TUPLE;
652
653        case INSTR_non_local:
654            {
655                PolyWord *t = sp+arg1;
656                POLYSIGNED uu;
657                for(uu = 1; uu <= arg2; uu++) t = (t[-1]).AsStackAddr();
658                uu = arg3; /* Can be negative. */
659                if (uu > 32767) uu -= 65536;
660                *(--sp) = t[uu];
661                pc += 6;
662                break;
663            }
664
665        case INSTR_local_w:
666            {
667                PolyWord u = sp[arg1];
668                *(--sp) = u;
669                pc += 2;
670                break;
671            }
672
673        case INSTR_indirect_w:
674            *sp = (*sp).AsObjPtr()->Get(arg1); pc += 2; break;
675
676        case INSTR_move_to_vec_w:
677            {
678                PolyWord u = *sp++;
679                (*sp).AsObjPtr()->Set(arg1, u);
680                pc += 2;
681                break;
682            }
683
684        case INSTR_set_stack_val_w:
685            {
686                PolyWord u = *sp++;
687                sp[arg1-1] = u;
688                pc += 2;
689                break;
690            }
691
692        case INSTR_reset_w: sp += arg1; pc += 2; break;
693
694        case INSTR_reset_r_w:
695            {
696                PolyWord u = *sp;
697                sp += arg1;
698                *sp = u;
699                pc += 2;
700                break;
701            }
702
703        case INSTR_constAddr8:
704            *(--sp) = *(PolyWord*)(pc + pc[0] + 1); pc += 1; break;
705
706        case INSTR_constAddr16:
707            *(--sp) = *(PolyWord*)(pc + arg1 + 2); pc += 2; break;
708
709        case INSTR_constAddr32:
710        {
711            POLYUNSIGNED offset = pc[0] + (pc[1] << 8) + (pc[2] << 16) + (pc[3] << 24);
712            *(--sp) = *(PolyWord*)(pc + offset + 4);
713            pc += 4;
714            break;
715        }
716
717        case INSTR_const_int_w: *(--sp) = TAGGED(arg1); pc += 2; break;
718
719        case INSTR_jump_back8:
720            pc -= *pc + 1;
721            if (this->interrupt_requested)
722            {
723                // Check for interrupt in case we're in a loop
724                this->interrupt_requested = false;
725                SaveInterpreterState(pc, sp);
726                return -1;
727            }
728            break;
729
730        case INSTR_jump_back16:
731            pc -= arg1 + 1;
732            if (this->interrupt_requested)
733            {
734                // Check for interrupt in case we're in a loop
735                this->interrupt_requested = false;
736                SaveInterpreterState(pc, sp);
737                return -1;
738            }
739            break;
740
741        case INSTR_lock:
742            {
743                PolyObject *obj = (*sp).AsObjPtr();
744                obj->SetLengthWord(obj->LengthWord() & ~_OBJ_MUTABLE_BIT);
745                break;
746            }
747
748        case INSTR_ldexc: *(--sp) = this->exception_arg; break;
749
750        case INSTR_local_b: { PolyWord u = sp[*pc]; *(--sp) = u; pc += 1; break; }
751
752        case INSTR_indirect_b:
753            *sp = (*sp).AsObjPtr()->Get(*pc); pc += 1; break;
754
755        case INSTR_move_to_vec_b:
756            { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(*pc, u); pc += 1; break; }
757
758        case INSTR_set_stack_val_b:
759            { PolyWord u = *sp++; sp[*pc-1] = u; pc += 1; break; }
760
761        case INSTR_reset_b: sp += *pc; pc += 1; break;
762
763        case INSTR_reset_r_b:
764            { PolyWord u = *sp; sp += *pc; *sp = u; pc += 1; break; }
765
766        case INSTR_const_int_b: *(--sp) = TAGGED(*pc); pc += 1; break;
767
768        case INSTR_local_0: { PolyWord u = sp[0]; *(--sp) = u; break; }
769        case INSTR_local_1: { PolyWord u = sp[1]; *(--sp) = u; break; }
770        case INSTR_local_2: { PolyWord u = sp[2]; *(--sp) = u; break; }
771        case INSTR_local_3: { PolyWord u = sp[3]; *(--sp) = u; break; }
772        case INSTR_local_4: { PolyWord u = sp[4]; *(--sp) = u; break; }
773        case INSTR_local_5: { PolyWord u = sp[5]; *(--sp) = u; break; }
774        case INSTR_local_6: { PolyWord u = sp[6]; *(--sp) = u; break; }
775        case INSTR_local_7: { PolyWord u = sp[7]; *(--sp) = u; break; }
776        case INSTR_local_8: { PolyWord u = sp[8]; *(--sp) = u; break; }
777        case INSTR_local_9: { PolyWord u = sp[9]; *(--sp) = u; break; }
778        case INSTR_local_10: { PolyWord u = sp[10]; *(--sp) = u; break; }
779        case INSTR_local_11: { PolyWord u = sp[11]; *(--sp) = u; break; }
780
781        case INSTR_indirect_0:
782            *sp = (*sp).AsObjPtr()->Get(0); break;
783
784        case INSTR_indirect_1:
785            *sp = (*sp).AsObjPtr()->Get(1); break;
786
787        case INSTR_indirect_2:
788            *sp = (*sp).AsObjPtr()->Get(2); break;
789
790        case INSTR_indirect_3:
791            *sp = (*sp).AsObjPtr()->Get(3); break;
792
793        case INSTR_indirect_4:
794            *sp = (*sp).AsObjPtr()->Get(4); break;
795
796        case INSTR_indirect_5:
797            *sp = (*sp).AsObjPtr()->Get(5); break;
798
799        case INSTR_const_0: *(--sp) = Zero; break;
800        case INSTR_const_1: *(--sp) = TAGGED(1); break;
801        case INSTR_const_2: *(--sp) = TAGGED(2); break;
802        case INSTR_const_3: *(--sp) = TAGGED(3); break;
803        case INSTR_const_4: *(--sp) = TAGGED(4); break;
804        case INSTR_const_10: *(--sp) = TAGGED(10); break;
805
806        case INSTR_move_to_vec_0:  { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(0, u); break; }
807        case INSTR_move_to_vec_1: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(1, u); break; }
808        case INSTR_move_to_vec_2: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(2, u); break; }
809        case INSTR_move_to_vec_3: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(3, u); break; }
810        case INSTR_move_to_vec_4: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(4, u); break; }
811        case INSTR_move_to_vec_5: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(5, u); break; }
812        case INSTR_move_to_vec_6: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(6, u); break; }
813        case INSTR_move_to_vec_7: { PolyWord u = *sp++; (*sp).AsObjPtr()->Set(7, u); break; }
814
815        case INSTR_reset_r_1: { PolyWord u = *sp; sp += 1; *sp = u; break; }
816        case INSTR_reset_r_2: { PolyWord u = *sp; sp += 2; *sp = u; break; }
817        case INSTR_reset_r_3: { PolyWord u = *sp; sp += 3; *sp = u; break; }
818
819        case INSTR_reset_1: sp += 1; break;
820        case INSTR_reset_2: sp += 2; break;
821
822        case INSTR_non_local_l_1:
823            {
824                POLYSIGNED uu = *pc;
825                PolyWord u = (sp[uu >> 4]).AsStackAddr()[(uu & 0xf) - 6];
826                *(--sp) = u;
827                pc += 1;
828                break;
829            }
830
831        case INSTR_non_local_l_2:
832            {
833                POLYSIGNED uu = *pc;
834                PolyWord *t = sp[uu >> 4].AsStackAddr() -1;
835                *(--sp) = (*t).AsStackAddr()[(uu & 0xf) - 6];
836                pc += 1;
837                break;
838            }
839
840        case INSTR_non_local_l_3:
841            {
842                POLYSIGNED uu = *pc;
843                PolyWord *t = sp[uu >> 4].AsStackAddr() -1;
844                t = (*t).AsStackAddr() - 1;
845                *(--sp) = (*t).AsStackAddr()[(uu & 0xf) - 6];
846                pc += 1; break;
847            }
848
849        case INSTR_stack_container:
850        {
851            POLYUNSIGNED words = arg1; pc += 2;
852            while (words-- > 0) *(--sp) = Zero;
853            sp--;
854            *sp = PolyWord::FromStackAddr(sp+1);
855            break;
856        }
857
858        case INSTR_tuple_container: /* Create a tuple from a container. */
859            {
860                storeWords = arg1;
861                PolyObject *t = this->allocateMemory(storeWords, pc, sp);
862                if (t == 0) goto RAISE_EXCEPTION;
863                t->SetLengthWord(storeWords, 0);
864                for(; storeWords > 0; )
865                {
866                    storeWords--;
867                    t->Set(storeWords, (*sp).AsObjPtr()->Get(storeWords));
868                }
869                *sp = t;
870                pc += 2;
871                break;
872            }
873
874        case INSTR_callFastRTS0:
875            {
876                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
877                callFastRts0 doCall = (callFastRts0)rtsCall.AsCodePtr();
878                POLYUNSIGNED result = doCall();
879                *(--sp) = PolyWord::FromUnsigned(result);
880                break;
881            }
882
883        case INSTR_callFastRTS1:
884            {
885                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
886                PolyWord rtsArg1 = *sp++;
887                callFastRts1 doCall = (callFastRts1)rtsCall.AsCodePtr();
888                POLYUNSIGNED result = doCall(rtsArg1);
889                *(--sp) = PolyWord::FromUnsigned(result);
890                break;
891            }
892
893        case INSTR_callFastRTS2:
894            {
895                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
896                PolyWord rtsArg2 = *sp++; // Pop off the args, last arg first.
897                PolyWord rtsArg1 = *sp++;
898                callFastRts2 doCall = (callFastRts2)rtsCall.AsCodePtr();
899                POLYUNSIGNED result = doCall(rtsArg1, rtsArg2);
900                *(--sp) = PolyWord::FromUnsigned(result);
901                break;
902            }
903
904        case INSTR_callFastRTS3:
905            {
906                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
907                PolyWord rtsArg3 = *sp++; // Pop off the args, last arg first.
908                PolyWord rtsArg2 = *sp++;
909                PolyWord rtsArg1 = *sp++;
910                callFastRts3 doCall = (callFastRts3)rtsCall.AsCodePtr();
911                POLYUNSIGNED result = doCall(rtsArg1, rtsArg2, rtsArg3);
912                *(--sp) = PolyWord::FromUnsigned(result);
913                break;
914            }
915
916        case INSTR_callFastRTS4:
917            {
918                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
919                PolyWord rtsArg4 = *sp++; // Pop off the args, last arg first.
920                PolyWord rtsArg3 = *sp++;
921                PolyWord rtsArg2 = *sp++;
922                PolyWord rtsArg1 = *sp++;
923                callFastRts4 doCall = (callFastRts4)rtsCall.AsCodePtr();
924                POLYUNSIGNED result = doCall(rtsArg1, rtsArg2, rtsArg3, rtsArg4);
925                *(--sp) = PolyWord::FromUnsigned(result);
926                break;
927            }
928
929        case INSTR_callFastRTS5:
930            {
931                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
932                PolyWord rtsArg5 = *sp++; // Pop off the args, last arg first.
933                PolyWord rtsArg4 = *sp++;
934                PolyWord rtsArg3 = *sp++;
935                PolyWord rtsArg2 = *sp++;
936                PolyWord rtsArg1 = *sp++;
937                callFastRts5 doCall = (callFastRts5)rtsCall.AsCodePtr();
938                POLYUNSIGNED result = doCall(rtsArg1, rtsArg2, rtsArg3, rtsArg4, rtsArg5);
939                *(--sp) = PolyWord::FromUnsigned(result);
940                break;
941            }
942
943        case INSTR_callFullRTS0:
944            {
945                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
946                callFullRts0 doCall = (callFullRts0)rtsCall.AsCodePtr();
947                this->raiseException = false;
948                SaveInterpreterState(pc, sp);
949                POLYUNSIGNED result = doCall(this->threadObject);
950                LoadInterpreterState(pc, sp);
951                // If this raised an exception
952                if (this->raiseException) goto RAISE_EXCEPTION;
953                *(--sp) = PolyWord::FromUnsigned(result);
954                break;
955            }
956
957        case INSTR_callFullRTS1:
958            {
959                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
960                PolyWord rtsArg1 = *sp++;
961                this->raiseException = false;
962                SaveInterpreterState(pc, sp);
963                callFullRts1 doCall = (callFullRts1)rtsCall.AsCodePtr();
964                POLYUNSIGNED result = doCall(this->threadObject, rtsArg1);
965                LoadInterpreterState(pc, sp);
966                // If this raised an exception
967                if (this->raiseException) goto RAISE_EXCEPTION;
968                *(--sp) = PolyWord::FromUnsigned(result);
969                break;
970            }
971
972        case INSTR_callFullRTS2:
973            {
974                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
975                PolyWord rtsArg2 = *sp++; // Pop off the args, last arg first.
976                PolyWord rtsArg1 = *sp++;
977                this->raiseException = false;
978                SaveInterpreterState(pc, sp);
979                callFullRts2 doCall = (callFullRts2)rtsCall.AsCodePtr();
980                POLYUNSIGNED result = doCall(this->threadObject, rtsArg1, rtsArg2);
981                LoadInterpreterState(pc, sp);
982                // If this raised an exception
983                if (this->raiseException) goto RAISE_EXCEPTION;
984                *(--sp) = PolyWord::FromUnsigned(result);
985                break;
986            }
987
988        case INSTR_callFullRTS3:
989            {
990                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
991                PolyWord rtsArg3 = *sp++; // Pop off the args, last arg first.
992                PolyWord rtsArg2 = *sp++;
993                PolyWord rtsArg1 = *sp++;
994                this->raiseException = false;
995                SaveInterpreterState(pc, sp);
996                callFullRts3 doCall = (callFullRts3)rtsCall.AsCodePtr();
997                POLYUNSIGNED result = doCall(this->threadObject, rtsArg1, rtsArg2, rtsArg3);
998                LoadInterpreterState(pc, sp);
999                // If this raised an exception
1000                if (this->raiseException) goto RAISE_EXCEPTION;
1001                *(--sp) = PolyWord::FromUnsigned(result);
1002                break;
1003            }
1004
1005        case INSTR_callFastFtoF:
1006            {
1007                // Floating point call.  The call itself does not allocate but we
1008                // need to put the result into a "box".
1009                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
1010                PolyWord rtsArg1 = *sp++;
1011                callRTSFtoF doCall = (callRTSFtoF)rtsCall.AsCodePtr();
1012                double argument = unboxDouble(rtsArg1);
1013                // Allocate memory for the result.
1014                double result = doCall(argument);
1015                PolyObject *t = boxDouble(result, pc, sp);
1016                if (t == 0) goto RAISE_EXCEPTION;
1017                *(--sp) = t;
1018                break;
1019            }
1020
1021        case INSTR_callFastGtoF:
1022            {
1023                // Call that takes a POLYUNSIGNED argument and returns a double.
1024                PolyWord rtsCall = (*sp++).AsObjPtr()->Get(0); // Value holds address.
1025                PolyWord rtsArg1 = *sp++;
1026                callRTSGtoF doCall = (callRTSGtoF)rtsCall.AsCodePtr();
1027                // Allocate memory for the result.
1028                double result = doCall(rtsArg1);
1029                PolyObject *t = boxDouble(result, pc, sp);
1030                if (t == 0) goto RAISE_EXCEPTION;
1031                *(--sp) = t;
1032                break;
1033            }
1034
1035        case INSTR_notBoolean:
1036            *sp = (*sp == True) ? False : True; break;
1037
1038        case INSTR_isTagged:
1039            *sp = IS_INT(*sp) ? True : False; break;
1040
1041        case INSTR_cellLength:
1042            /* Return the length word. */
1043            *sp = TAGGED((*sp).AsObjPtr()->Length());
1044            break;
1045
1046        case INSTR_cellFlags:
1047        {
1048            PolyObject *p = (*sp).AsObjPtr();
1049            POLYUNSIGNED f = (p->LengthWord()) >> OBJ_PRIVATE_FLAGS_SHIFT;
1050            *sp = TAGGED(f);
1051            break;
1052        }
1053
1054        case INSTR_clearMutable:
1055        {
1056            PolyObject *obj = (*sp).AsObjPtr();
1057            POLYUNSIGNED lengthW = obj->LengthWord();
1058            /* Clear the mutable bit. */
1059            obj->SetLengthWord(lengthW & ~_OBJ_MUTABLE_BIT);
1060            *sp = Zero;
1061            break;
1062        }
1063
1064        case INSTR_stringLength: // Now replaced by loadUntagged
1065            *sp = TAGGED(((PolyStringObject*)(*sp).AsObjPtr())->length);
1066            break;
1067
1068        case INSTR_atomicIncr:
1069        {
1070            PLocker l(&mutexLock);
1071            PolyObject *p = (*sp).AsObjPtr();
1072            PolyWord newValue = TAGGED(UNTAGGED(p->Get(0))+1);
1073            p->Set(0, newValue);
1074            *sp = newValue;
1075            break;
1076        }
1077
1078        case INSTR_atomicDecr:
1079        {
1080            PLocker l(&mutexLock);
1081            PolyObject *p = (*sp).AsObjPtr();
1082            PolyWord newValue = TAGGED(UNTAGGED(p->Get(0))-1);
1083            p->Set(0, newValue);
1084            *sp = newValue;
1085            break;
1086        }
1087
1088        case INSTR_atomicReset:
1089        {
1090            // This is needed in the interpreted version otherwise there
1091            // is a chance that we could set the value to zero while another
1092            // thread is between getting the old value and setting it to the new value.
1093            PLocker l(&mutexLock);
1094            PolyObject *p = (*sp).AsObjPtr();
1095            p->Set(0, TAGGED(1)); // Set this to released.
1096            *sp = TAGGED(0); // Push the unit result
1097            break;
1098        }
1099
1100        case INSTR_longWToTagged:
1101        {
1102            // Extract the first word and return it as a tagged value.  This loses the top-bit
1103            POLYUNSIGNED wx = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1104            *sp = TAGGED(wx);
1105            break;
1106        }
1107
1108        case INSTR_signedToLongW:
1109        {
1110            // Shift the tagged value to remove the tag and put it into the first word.
1111            // The original sign bit is copied in the shift.
1112            POLYSIGNED wx = (*sp).UnTagged();
1113            PolyObject *t = this->allocateMemory(1, pc, sp);
1114            if (t == 0) goto RAISE_EXCEPTION;
1115            t->SetLengthWord(1, F_BYTE_OBJ);
1116            t->Set(0, PolyWord::FromSigned(wx));
1117            *sp = t;
1118            break;
1119        }
1120
1121        case INSTR_unsignedToLongW:
1122        {
1123            // As with the above except the value is treated as an unsigned
1124            // value and the top bit is zero.
1125            POLYUNSIGNED wx = (*sp).UnTaggedUnsigned();
1126            PolyObject *t = this->allocateMemory(1, pc, sp);
1127            if (t == 0) goto RAISE_EXCEPTION;
1128            t->SetLengthWord(1, F_BYTE_OBJ);
1129            t->Set(0, PolyWord::FromUnsigned(wx));
1130            *sp = t;
1131            break;
1132        }
1133
1134        case INSTR_realAbs:
1135        {
1136            PolyObject *t = this->boxDouble(fabs(unboxDouble(*sp)), pc, sp);
1137            if (t == 0) goto RAISE_EXCEPTION;
1138            *sp = t;
1139            break;
1140        }
1141
1142        case INSTR_realNeg:
1143        {
1144            PolyObject *t = this->boxDouble(-(unboxDouble(*sp)), pc, sp);
1145            if (t == 0) goto RAISE_EXCEPTION;
1146            *sp = t;
1147            break;
1148        }
1149
1150        case INSTR_floatFixedInt:
1151        {
1152            POLYSIGNED u = UNTAGGED(*sp);
1153            PolyObject *t = this->boxDouble((double)u, pc, sp);
1154            if (t == 0) goto RAISE_EXCEPTION;
1155            *sp = t;
1156            break;
1157        }
1158
1159        case INSTR_equalWord:
1160        {
1161            PolyWord u = *sp++;
1162            *sp = u == *sp ? True : False;
1163            break;
1164        }
1165
1166        case INSTR_lessSigned:
1167        {
1168            PolyWord u = *sp++;
1169            *sp = ((*sp).AsSigned() < u.AsSigned()) ? True : False;
1170            break;
1171        }
1172
1173        case INSTR_lessUnsigned:
1174        {
1175            PolyWord u = *sp++;
1176            *sp = ((*sp).AsUnsigned() < u.AsUnsigned()) ? True : False;
1177            break;
1178        }
1179
1180        case INSTR_lessEqSigned:
1181        {
1182            PolyWord u = *sp++;
1183            *sp = ((*sp).AsSigned() <= u.AsSigned()) ? True : False;
1184            break;
1185        }
1186
1187        case INSTR_lessEqUnsigned:
1188        {
1189            PolyWord u = *sp++;
1190            *sp = ((*sp).AsUnsigned() <= u.AsUnsigned()) ? True : False;
1191            break;
1192        }
1193
1194        case INSTR_greaterSigned:
1195        {
1196            PolyWord u = *sp++;
1197            *sp = ((*sp).AsSigned() > u.AsSigned()) ? True : False;
1198            break;
1199        }
1200
1201        case INSTR_greaterUnsigned:
1202        {
1203            PolyWord u = *sp++;
1204            *sp = ((*sp).AsUnsigned() > u.AsUnsigned()) ? True : False;
1205            break;
1206        }
1207
1208        case INSTR_greaterEqSigned:
1209        {
1210            PolyWord u = *sp++;
1211            *sp = ((*sp).AsSigned() >= u.AsSigned()) ? True : False;
1212            break;
1213        }
1214
1215        case INSTR_greaterEqUnsigned:
1216        {
1217            PolyWord u = *sp++;
1218            *sp = ((*sp).AsUnsigned() >= u.AsUnsigned()) ? True : False;
1219            break;
1220        }
1221
1222        case INSTR_fixedAdd:
1223        {
1224            PolyWord x = *sp++;
1225            PolyWord y = *sp;
1226            POLYSIGNED t = UNTAGGED(x) + UNTAGGED(y);
1227            if (t <= MAXTAGGED && t >= -MAXTAGGED-1)
1228                *sp = TAGGED(t);
1229            else
1230            {
1231                *(--sp) = overflowPacket;
1232                goto RAISE_EXCEPTION;
1233            }
1234            break;
1235        }
1236
1237        case INSTR_fixedSub:
1238        {
1239            PolyWord x = *sp++;
1240            PolyWord y = *sp;
1241            POLYSIGNED t = UNTAGGED(y) - UNTAGGED(x);
1242            if (t <= MAXTAGGED && t >= -MAXTAGGED-1)
1243                *sp = TAGGED(t);
1244            else
1245            {
1246                *(--sp) = overflowPacket;
1247                goto RAISE_EXCEPTION;
1248            }
1249            break;
1250        }
1251
1252        case INSTR_fixedMult:
1253        {
1254            // We need to detect overflow.  There doesn't seem to be any convenient way to do
1255            // this so we use the arbitrary precision package and check whether the result is short.
1256            // Clang and GCC 5.0 have __builtin_mul_overflow which will do this but GCC 5.0 is not
1257            // currently (July 2016) in Debian stable.
1258            Handle reset = this->saveVec.mark();
1259            Handle pushedArg1 = this->saveVec.push(*sp++);
1260            Handle pushedArg2 = this->saveVec.push(*sp);
1261            Handle result = mult_longc(this, pushedArg2, pushedArg1);
1262            PolyWord res = result->Word();
1263            this->saveVec.reset(reset);
1264            if (! res.IsTagged())
1265            {
1266                *(--sp) = overflowPacket;
1267                goto RAISE_EXCEPTION;
1268            }
1269            *sp = res;
1270            break;
1271        }
1272
1273        case INSTR_fixedQuot:
1274        {
1275            // Zero and overflow are checked for in ML.
1276            POLYSIGNED u = UNTAGGED(*sp++);
1277            PolyWord y = *sp;
1278            *sp = TAGGED(UNTAGGED(y) / u);
1279            break;
1280        }
1281
1282        case INSTR_fixedRem:
1283        {
1284            // Zero and overflow are checked for in ML.
1285            POLYSIGNED u = UNTAGGED(*sp++);
1286            PolyWord y = *sp;
1287            *sp = TAGGED(UNTAGGED(y) % u);
1288            break;
1289        }
1290
1291        case INSTR_wordAdd:
1292        {
1293            PolyWord u = *sp++;
1294            // Because we're not concerned with overflow we can just add the values and subtract the tag.
1295            *sp = PolyWord::FromUnsigned((*sp).AsUnsigned() + u.AsUnsigned() - TAGGED(0).AsUnsigned());
1296            break;
1297        }
1298
1299        case INSTR_wordSub:
1300        {
1301            PolyWord u = *sp++;
1302            *sp = PolyWord::FromUnsigned((*sp).AsUnsigned() - u.AsUnsigned() + TAGGED(0).AsUnsigned());
1303            break;
1304        }
1305
1306        case INSTR_wordMult:
1307        {
1308            PolyWord u = *sp++;
1309            *sp = TAGGED(UNTAGGED_UNSIGNED(*sp) * UNTAGGED_UNSIGNED(u));
1310            break;
1311        }
1312
1313        case INSTR_wordDiv:
1314        {
1315            POLYUNSIGNED u = UNTAGGED_UNSIGNED(*sp++);
1316            // Detection of zero is done in ML
1317            *sp = TAGGED(UNTAGGED_UNSIGNED(*sp) / u); break;
1318        }
1319
1320        case INSTR_wordMod:
1321        {
1322            POLYUNSIGNED u = UNTAGGED_UNSIGNED(*sp++);
1323            *sp = TAGGED(UNTAGGED_UNSIGNED(*sp) % u);
1324            break;
1325        }
1326
1327        case INSTR_wordAnd:
1328        {
1329            PolyWord u = *sp++;
1330            // Since both of these should be tagged the tag bit will be preserved.
1331            *sp = PolyWord::FromUnsigned((*sp).AsUnsigned() & u.AsUnsigned());
1332            break;
1333        }
1334
1335        case INSTR_wordOr:
1336        {
1337            PolyWord u = *sp++;
1338            // Since both of these should be tagged the tag bit will be preserved.
1339            *sp = PolyWord::FromUnsigned((*sp).AsUnsigned() | u.AsUnsigned());
1340            break;
1341        }
1342
1343        case INSTR_wordXor:
1344        {
1345            PolyWord u = *sp++;
1346            // This will remove the tag bit so it has to be reinstated.
1347            *sp = PolyWord::FromUnsigned(((*sp).AsUnsigned() ^ u.AsUnsigned()) | TAGGED(0).AsUnsigned());
1348            break;
1349        }
1350
1351        case INSTR_wordShiftLeft:
1352        {
1353            // ML requires shifts greater than a word to return zero.
1354            // That's dealt with at the higher level.
1355            PolyWord u = *sp++;
1356            *sp = TAGGED(UNTAGGED_UNSIGNED(*sp) << UNTAGGED_UNSIGNED(u));
1357            break;
1358        }
1359
1360        case INSTR_wordShiftRLog:
1361        {
1362            PolyWord u = *sp++;
1363            *sp = TAGGED(UNTAGGED_UNSIGNED(*sp) >> UNTAGGED_UNSIGNED(u));
1364            break;
1365        }
1366
1367        case INSTR_wordShiftRArith:
1368        {
1369            PolyWord u = *sp++;
1370            // Strictly speaking, C does not require that this uses
1371            // arithmetic shifting so we really ought to set the
1372            // high-order bits explicitly.
1373            *sp = TAGGED(UNTAGGED(*sp) >> UNTAGGED(u));
1374            break;
1375        }
1376
1377        case INSTR_allocByteMem:
1378        {
1379            // Allocate byte segment.  This does not need to be initialised.
1380            POLYUNSIGNED flags = UNTAGGED_UNSIGNED(*sp++);
1381            POLYUNSIGNED length = UNTAGGED_UNSIGNED(*sp);
1382            PolyObject *t = this->allocateMemory(length, pc, sp);
1383            if (t == 0) goto RAISE_EXCEPTION; // Exception
1384            t->SetLengthWord(length, (byte)flags);
1385            *sp = t;
1386            break;
1387        }
1388
1389        case INSTR_lgWordEqual:
1390        {
1391            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1392            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1393            *sp = wx == wy ? True : False;
1394            break;
1395        }
1396
1397        case INSTR_lgWordNotequal:
1398        {
1399            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1400            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1401            *sp = wx != wy ? True : False;
1402            break;
1403        }
1404
1405        case INSTR_lgWordLess:
1406        {
1407            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1408            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1409            *sp = (wy < wx) ? True : False;
1410            break;
1411        }
1412
1413        case INSTR_lgWordLessEq:
1414        {
1415            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1416            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1417            *sp = (wy <= wx) ? True : False;
1418            break;
1419        }
1420
1421        case INSTR_lgWordGreater:
1422        {
1423            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1424            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1425            *sp = (wy > wx) ? True : False;
1426            break;
1427        }
1428
1429        case INSTR_lgWordGreaterEq:
1430        {
1431            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1432            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1433            *sp = (wy >= wx) ? True : False;
1434            break;
1435        }
1436
1437        case INSTR_lgWordAdd:
1438        {
1439            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1440            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1441            PolyObject *t = this->allocateMemory(1, pc, sp);
1442            if (t == 0) goto RAISE_EXCEPTION;
1443            t->SetLengthWord(1, F_BYTE_OBJ);
1444            t->Set(0, PolyWord::FromUnsigned(wy+wx));
1445            *sp = t;
1446            break;
1447        }
1448
1449        case INSTR_lgWordSub:
1450        {
1451            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1452            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1453            PolyObject *t = this->allocateMemory(1, pc, sp);
1454            if (t == 0) goto RAISE_EXCEPTION;
1455            t->SetLengthWord(1, F_BYTE_OBJ);
1456            t->Set(0, PolyWord::FromUnsigned(wy-wx));
1457            *sp = t;
1458            break;
1459        }
1460
1461        case INSTR_lgWordMult:
1462        {
1463            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1464            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1465            PolyObject *t = this->allocateMemory(1, pc, sp);
1466            if (t == 0) goto RAISE_EXCEPTION;
1467            t->SetLengthWord(1, F_BYTE_OBJ);
1468            t->Set(0, PolyWord::FromUnsigned(wy*wx));
1469            *sp = t;
1470            break;
1471        }
1472
1473        case INSTR_lgWordDiv:
1474         {
1475            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1476            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1477            PolyObject *t = this->allocateMemory(1, pc, sp);
1478            if (t == 0) goto RAISE_EXCEPTION;
1479            t->SetLengthWord(1, F_BYTE_OBJ);
1480            t->Set(0, PolyWord::FromUnsigned(wy/wx));
1481            *sp = t;
1482            break;
1483        }
1484
1485        case INSTR_lgWordMod:
1486        {
1487            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1488            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1489            PolyObject *t = this->allocateMemory(1, pc, sp);
1490            if (t == 0) goto RAISE_EXCEPTION;
1491            t->SetLengthWord(1, F_BYTE_OBJ);
1492            t->Set(0, PolyWord::FromUnsigned(wy%wx));
1493            *sp = t;
1494            break;
1495        }
1496
1497        case INSTR_lgWordAnd:
1498        {
1499            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1500            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1501            PolyObject *t = this->allocateMemory(1, pc, sp);
1502            if (t == 0) goto RAISE_EXCEPTION;
1503            t->SetLengthWord(1, F_BYTE_OBJ);
1504            t->Set(0, PolyWord::FromUnsigned(wy&wx));
1505            *sp = t;
1506            break;
1507        }
1508
1509        case INSTR_lgWordOr:
1510        {
1511            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1512            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1513            PolyObject *t = this->allocateMemory(1, pc, sp);
1514            if (t == 0) goto RAISE_EXCEPTION;
1515            t->SetLengthWord(1, F_BYTE_OBJ);
1516            t->Set(0, PolyWord::FromUnsigned(wy|wx));
1517            *sp = t;
1518            break;
1519        }
1520
1521        case INSTR_lgWordXor:
1522        {
1523            POLYUNSIGNED wx = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1524            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1525            PolyObject *t = this->allocateMemory(1, pc, sp);
1526            if (t == 0) goto RAISE_EXCEPTION;
1527            t->SetLengthWord(1, F_BYTE_OBJ);
1528            t->Set(0, PolyWord::FromUnsigned(wy^wx));
1529            *sp = t;
1530            break;
1531        }
1532
1533        case INSTR_lgWordShiftLeft:
1534        {
1535            // The shift amount is a tagged word not a boxed large word
1536            POLYUNSIGNED wx = UNTAGGED_UNSIGNED(*sp++);
1537            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1538            PolyObject *t = this->allocateMemory(1, pc, sp);
1539            if (t == 0) goto RAISE_EXCEPTION;
1540            t->SetLengthWord(1, F_BYTE_OBJ);
1541            t->Set(0, PolyWord::FromUnsigned(wy << wx));
1542            *sp = t;
1543            break;
1544        }
1545
1546        case INSTR_lgWordShiftRLog:
1547        {
1548            // The shift amount is a tagged word not a boxed large word
1549            POLYUNSIGNED wx = UNTAGGED_UNSIGNED(*sp++);
1550            POLYUNSIGNED wy = (*sp).AsObjPtr()->Get(0).AsUnsigned();
1551            PolyObject *t = this->allocateMemory(1, pc, sp);
1552            if (t == 0) goto RAISE_EXCEPTION;
1553            t->SetLengthWord(1, F_BYTE_OBJ);
1554            t->Set(0, PolyWord::FromUnsigned(wy >> wx));
1555            *sp = t;
1556            break;
1557        }
1558
1559        case INSTR_lgWordShiftRArith:
1560        {
1561            // The shift amount is a tagged word not a boxed large word
1562            POLYUNSIGNED wx = UNTAGGED_UNSIGNED(*sp++);
1563            POLYSIGNED wy = (*sp).AsObjPtr()->Get(0).AsSigned();
1564            PolyObject *t = this->allocateMemory(1, pc, sp);
1565            if (t == 0) goto RAISE_EXCEPTION;
1566            t->SetLengthWord(1, F_BYTE_OBJ);
1567            t->Set(0, PolyWord::FromSigned(wy >> wx));
1568            *sp = t;
1569            break;
1570        }
1571
1572        case INSTR_realEqual:
1573        {
1574            double u = unboxDouble(*sp++);
1575            *sp = u == unboxDouble(*sp) ? True: False;
1576            break;
1577        }
1578
1579        case INSTR_realLess:
1580        {
1581            double u = unboxDouble(*sp++);
1582            *sp =  unboxDouble(*sp) < u ? True: False;
1583            break;
1584        }
1585
1586        case INSTR_realLessEq:
1587        {
1588            double u = unboxDouble(*sp++);
1589            *sp =  unboxDouble(*sp) <= u ? True: False;
1590            break;
1591        }
1592
1593        case INSTR_realGreater:
1594        {
1595            double u = unboxDouble(*sp++);
1596            *sp =  unboxDouble(*sp) > u ? True: False;
1597            break;
1598        }
1599
1600        case INSTR_realGreaterEq:
1601        {
1602            double u = unboxDouble(*sp++);
1603            *sp =  unboxDouble(*sp) >= u ? True: False;
1604            break;
1605        }
1606
1607        case INSTR_realAdd:
1608        {
1609            double u = unboxDouble(*sp++);
1610            double v = unboxDouble(*sp);
1611            PolyObject *t = this->boxDouble(v+u, pc, sp);
1612            if (t == 0) goto RAISE_EXCEPTION;
1613            *sp = t;
1614            break;
1615        }
1616
1617        case INSTR_realSub:
1618        {
1619            double u = unboxDouble(*sp++);
1620            double v = unboxDouble(*sp);
1621            PolyObject *t = this->boxDouble(v-u, pc, sp);
1622            if (t == 0) goto RAISE_EXCEPTION;
1623            *sp = t;
1624            break;
1625        }
1626
1627        case INSTR_realMult:
1628        {
1629            double u = unboxDouble(*sp++);
1630            double v = unboxDouble(*sp);
1631            PolyObject *t = this->boxDouble(v*u, pc, sp);
1632            if (t == 0) goto RAISE_EXCEPTION;
1633            *sp = t;
1634            break;
1635        }
1636
1637        case INSTR_realDiv:
1638        {
1639            double u = unboxDouble(*sp++);
1640            double v = unboxDouble(*sp);
1641            PolyObject *t = this->boxDouble(v/u, pc, sp);
1642            if (t == 0) goto RAISE_EXCEPTION;
1643            *sp = t;
1644            break;
1645        }
1646
1647        case INSTR_getThreadId:
1648            *(--sp) = this->threadObject;
1649            break;
1650
1651        case INSTR_allocWordMemory:
1652        {
1653            // Allocate word segment.  This must be initialised.
1654            // We mustn't pop the initialiser until after any potential GC.
1655            POLYUNSIGNED length = UNTAGGED_UNSIGNED(sp[2]);
1656            PolyObject *t = this->allocateMemory(length, pc, sp);
1657            if (t == 0) goto RAISE_EXCEPTION;
1658            PolyWord initialiser = *sp++;
1659            POLYUNSIGNED flags = UNTAGGED_UNSIGNED(*sp++);
1660            t->SetLengthWord(length, (byte)flags);
1661            *sp = t;
1662            // Have to initialise the data.
1663            for (; length > 0; ) t->Set(--length, initialiser);
1664            break;
1665        }
1666
1667        case INSTR_alloc_ref:
1668        {
1669            // Allocate a single word mutable cell.  This is more common than allocWordMemory on its own.
1670            PolyObject *t = this->allocateMemory(1, pc, sp);
1671            if (t == 0) goto RAISE_EXCEPTION;
1672            PolyWord initialiser = *sp;
1673            t->SetLengthWord(1, F_MUTABLE_BIT);
1674            t->Set(0, initialiser);
1675            *sp = t;
1676            break;
1677        }
1678
1679        case INSTR_loadMLWord:
1680        {
1681            // The values on the stack are base, index and offset.
1682            POLYUNSIGNED offset = UNTAGGED(*sp++);
1683            POLYUNSIGNED index = UNTAGGED(*sp++);
1684            PolyObject *p = (PolyObject*)((*sp).AsCodePtr() + offset);
1685            *sp = p->Get(index);
1686            break;
1687        }
1688
1689        case INSTR_loadMLByte:
1690        {
1691            // The values on the stack are base and index.
1692            POLYUNSIGNED index = UNTAGGED(*sp++);
1693            POLYCODEPTR p = (*sp).AsCodePtr();
1694            *sp = TAGGED(p[index]); // Have to tag the result
1695            break;
1696        }
1697
1698        case INSTR_loadC8:
1699        {
1700            // This is similar to loadMLByte except that the base address is a boxed large-word.
1701            // Also the index is SIGNED.
1702            POLYSIGNED index = UNTAGGED(*sp++);
1703            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr();
1704            *sp = TAGGED(p[index]); // Have to tag the result
1705            break;
1706        }
1707
1708        case INSTR_loadC16:
1709        {
1710            // This and the other loads are similar to loadMLWord with separate
1711            // index and offset values.
1712            POLYSIGNED offset = UNTAGGED(*sp++);
1713            POLYSIGNED index = UNTAGGED(*sp++);
1714            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1715            POLYUNSIGNED r = ((uint16_t*)p)[index];
1716            *sp = TAGGED(r);
1717            break;
1718        }
1719
1720        case INSTR_loadC32:
1721        {
1722            POLYSIGNED offset = UNTAGGED(*sp++);
1723            POLYSIGNED index = UNTAGGED(*sp++);
1724            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1725            POLYUNSIGNED r = ((uint32_t*)p)[index];
1726#if (SIZEOF_VOIDP == 8)
1727            // This is tagged in 64-bit mode
1728            *sp = TAGGED(r);
1729#else
1730            // But boxed in 32-bit mode.
1731            PolyObject *t = this->allocateMemory(1, pc, sp);
1732            if (t == 0) goto RAISE_EXCEPTION;
1733            t->SetLengthWord(1, F_BYTE_OBJ);
1734            t->Set(0, PolyWord::FromUnsigned(r));
1735            *sp = t;
1736#endif
1737            break;
1738        }
1739#if (SIZEOF_VOIDP == 8)
1740        case INSTR_loadC64:
1741        {
1742            POLYSIGNED offset = UNTAGGED(*sp++);
1743            POLYSIGNED index = UNTAGGED(*sp++);
1744            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1745            POLYUNSIGNED r = ((uint64_t*)p)[index];
1746            // This must be boxed.
1747            PolyObject *t = this->allocateMemory(1, pc, sp);
1748            if (t == 0) goto RAISE_EXCEPTION;
1749            t->SetLengthWord(1, F_BYTE_OBJ);
1750            t->Set(0, PolyWord::FromUnsigned(r));
1751            *sp = t;
1752            break;
1753        }
1754#endif
1755
1756        case INSTR_loadCFloat:
1757        {
1758            POLYSIGNED offset = UNTAGGED(*sp++);
1759            POLYSIGNED index = UNTAGGED(*sp++);
1760            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1761            double r = ((float*)p)[index];
1762            // This must be boxed.
1763            PolyObject *t = this->boxDouble(r, pc, sp);
1764            if (t == 0) goto RAISE_EXCEPTION;
1765            *sp = t;
1766            break;
1767        }
1768
1769        case INSTR_loadCDouble:
1770        {
1771            POLYSIGNED offset = UNTAGGED(*sp++);
1772            POLYSIGNED index = UNTAGGED(*sp++);
1773            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1774            double r = ((double*)p)[index];
1775            // This must be boxed.
1776            PolyObject *t = this->boxDouble(r, pc, sp);
1777            if (t == 0) goto RAISE_EXCEPTION;
1778            *sp = t;
1779            break;
1780        }
1781
1782        case INSTR_loadUntagged:
1783        {
1784            // The values on the stack are base, index and offset.
1785            POLYUNSIGNED offset = UNTAGGED(*sp++);
1786            POLYUNSIGNED index = UNTAGGED(*sp++);
1787            PolyObject *p = (PolyObject*)((*sp).AsCodePtr() + offset);
1788            *sp = TAGGED(p->Get(index).AsUnsigned());
1789            break;
1790        }
1791
1792        case INSTR_storeMLWord:
1793        {
1794            PolyWord toStore = *sp++;
1795            POLYUNSIGNED offset = UNTAGGED(*sp++);
1796            POLYUNSIGNED index = UNTAGGED(*sp++);
1797            PolyObject *p = (PolyObject*)((*sp).AsCodePtr() + offset);
1798            p->Set(index, toStore);
1799            *sp = Zero;
1800            break;
1801        }
1802
1803        case INSTR_storeMLByte:
1804        {
1805            POLYUNSIGNED toStore = UNTAGGED(*sp++);
1806            POLYUNSIGNED index = UNTAGGED(*sp++);
1807            POLYCODEPTR p = (*sp).AsCodePtr();
1808            p[index] = (byte)toStore;
1809            *sp = Zero;
1810            break;
1811        }
1812
1813        case INSTR_storeC8:
1814        {
1815            // Similar to storeMLByte except that the base address is a boxed large-word.
1816            POLYUNSIGNED toStore = UNTAGGED(*sp++);
1817            POLYSIGNED index = UNTAGGED(*sp++);
1818            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr();
1819            p[index] = (byte)toStore;
1820            *sp = Zero;
1821            break;
1822        }
1823
1824        case INSTR_storeC16:
1825        {
1826            uint16_t toStore = (uint16_t)UNTAGGED(*sp++);
1827            POLYSIGNED offset = UNTAGGED(*sp++);
1828            POLYSIGNED index = UNTAGGED(*sp++);
1829            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1830            ((uint16_t*)p)[index] = toStore;
1831            *sp = Zero;
1832            break;
1833        }
1834
1835        case INSTR_storeC32:
1836        {
1837#if (SIZEOF_VOIDP == 8)
1838            // This is a tagged value in 64-bit mode.
1839            uint32_t toStore = (uint32_t)UNTAGGED(*sp++);
1840#else
1841            // but a boxed value in 32-bit mode.
1842            uint32_t toStore = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1843#endif
1844            POLYSIGNED offset = UNTAGGED(*sp++);
1845            POLYSIGNED index = UNTAGGED(*sp++);
1846            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1847            ((uint32_t*)p)[index] = toStore;
1848            *sp = Zero;
1849            break;
1850        }
1851
1852#if (SIZEOF_VOIDP == 8)
1853        case INSTR_storeC64:
1854        {
1855            // This is a boxed value.
1856            uint64_t toStore = (*sp++).AsObjPtr()->Get(0).AsUnsigned();
1857            POLYSIGNED offset = UNTAGGED(*sp++);
1858            POLYSIGNED index = UNTAGGED(*sp++);
1859            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1860            ((uint64_t*)p)[index] = toStore;
1861            *sp = Zero;
1862            break;
1863        }
1864#endif
1865
1866        case INSTR_storeCFloat:
1867        {
1868            // This is a boxed value.
1869            float toStore = (float)unboxDouble(*sp++);
1870            POLYSIGNED offset = UNTAGGED(*sp++);
1871            POLYSIGNED index = UNTAGGED(*sp++);
1872            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1873            ((float*)p)[index] = toStore;
1874            *sp = Zero;
1875            break;
1876        }
1877
1878        case INSTR_storeCDouble:
1879        {
1880            // This is a boxed value.
1881            double toStore = unboxDouble(*sp++);
1882            POLYSIGNED offset = UNTAGGED(*sp++);
1883            POLYSIGNED index = UNTAGGED(*sp++);
1884            POLYCODEPTR p = (*sp).AsObjPtr()->Get(0).AsCodePtr() + offset;
1885            ((double*)p)[index] = toStore;
1886            *sp = Zero;
1887            break;
1888        }
1889
1890        case INSTR_storeUntagged:
1891        {
1892            PolyWord toStore = PolyWord::FromUnsigned(UNTAGGED_UNSIGNED(*sp++));
1893            POLYUNSIGNED offset = UNTAGGED(*sp++);
1894            POLYUNSIGNED index = UNTAGGED(*sp++);
1895            PolyObject *p = (PolyObject*)((*sp).AsCodePtr() + offset);
1896            p->Set(index, toStore);
1897            *sp = Zero;
1898            break;
1899        }
1900
1901        case INSTR_blockMoveWord:
1902        {
1903            // The offsets are byte counts but the the indexes are in words.
1904            POLYUNSIGNED length = UNTAGGED_UNSIGNED(*sp++);
1905            POLYUNSIGNED destOffset = UNTAGGED_UNSIGNED(*sp++);
1906            POLYUNSIGNED destIndex = UNTAGGED_UNSIGNED(*sp++);
1907            PolyObject *dest = (PolyObject*)((*sp++).AsCodePtr() + destOffset);
1908            POLYUNSIGNED srcOffset = UNTAGGED_UNSIGNED(*sp++);
1909            POLYUNSIGNED srcIndex = UNTAGGED_UNSIGNED(*sp++);
1910            PolyObject *src = (PolyObject*)((*sp).AsCodePtr() + srcOffset);
1911            for (POLYUNSIGNED u = 0; u < length; u++) dest->Set(destIndex+u, src->Get(srcIndex+u));
1912            *sp = Zero;
1913            break;
1914        }
1915
1916        case INSTR_blockMoveByte:
1917        {
1918            POLYUNSIGNED length = UNTAGGED_UNSIGNED(*sp++);
1919            POLYUNSIGNED destOffset = UNTAGGED_UNSIGNED(*sp++);
1920            POLYCODEPTR dest = (*sp++).AsCodePtr();
1921            POLYUNSIGNED srcOffset = UNTAGGED_UNSIGNED(*sp++);
1922            POLYCODEPTR src = (*sp).AsCodePtr();
1923            memcpy(dest+destOffset, src+srcOffset, length);
1924            *sp = Zero;
1925            break;
1926        }
1927
1928        case INSTR_blockEqualByte:
1929        {
1930            POLYUNSIGNED length = UNTAGGED_UNSIGNED(*sp++);
1931            POLYUNSIGNED arg2Offset = UNTAGGED_UNSIGNED(*sp++);
1932            POLYCODEPTR arg2Ptr = (*sp++).AsCodePtr();
1933            POLYUNSIGNED arg1Offset = UNTAGGED_UNSIGNED(*sp++);
1934            POLYCODEPTR arg1Ptr = (*sp).AsCodePtr();
1935            *sp = memcmp(arg1Ptr+arg1Offset, arg2Ptr+arg2Offset, length) == 0 ? True : False;
1936            break;
1937        }
1938
1939        case INSTR_blockCompareByte:
1940        {
1941            POLYUNSIGNED length = UNTAGGED_UNSIGNED(*sp++);
1942            POLYUNSIGNED arg2Offset = UNTAGGED_UNSIGNED(*sp++);
1943            POLYCODEPTR arg2Ptr = (*sp++).AsCodePtr();
1944            POLYUNSIGNED arg1Offset = UNTAGGED_UNSIGNED(*sp++);
1945            POLYCODEPTR arg1Ptr = (*sp).AsCodePtr();
1946            int result = memcmp(arg1Ptr+arg1Offset, arg2Ptr+arg2Offset, length);
1947            *sp = result == 0 ? TAGGED(0) : result < 0 ? TAGGED(-1) : TAGGED(1);
1948            break;
1949        }
1950
1951        default: Crash("Unknown instruction %x\n", pc[-1]);
1952
1953        } /* switch */
1954     } /* for */
1955     return 0;
1956} /* MD_switch_to_poly */
1957
1958void IntTaskData::GarbageCollect(ScanAddress *process)
1959{
1960    TaskData::GarbageCollect(process);
1961
1962    overflowPacket = process->ScanObjectAddress(overflowPacket);
1963    dividePacket = process->ScanObjectAddress(dividePacket);
1964
1965    if (stack != 0)
1966    {
1967        StackSpace *stackSpace = stack;
1968        PolyWord *stackPtr = this->taskSp;
1969        // The exception arg if any
1970        ScanStackAddress(process, this->exception_arg, stackSpace);
1971
1972        // Now the values on the stack.
1973        for (PolyWord *q = stackPtr; q < stackSpace->top; q++)
1974            ScanStackAddress(process, *q, stackSpace);
1975     }
1976}
1977
1978
1979// Process a value within the stack.
1980void IntTaskData::ScanStackAddress(ScanAddress *process, PolyWord &val, StackSpace *stack)
1981{
1982    if (! val.IsDataPtr()) return;
1983
1984    MemSpace *space = gMem.LocalSpaceForAddress(val.AsStackAddr()-1);
1985    if (space != 0)
1986        val = process->ScanObjectAddress(val.AsObjPtr());
1987}
1988
1989
1990// Copy a stack
1991void IntTaskData::CopyStackFrame(StackObject *old_stack, POLYUNSIGNED old_length, StackObject *new_stack, POLYUNSIGNED new_length)
1992{
1993  /* Moves a stack, updating all references within the stack */
1994    PolyWord *old_base  = (PolyWord *)old_stack;
1995    PolyWord *new_base  = (PolyWord*)new_stack;
1996    PolyWord *old_top   = old_base + old_length;
1997
1998    /* Calculate the offset of the new stack from the old. If the frame is
1999       being extended objects in the new frame will be further up the stack
2000       than in the old one. */
2001
2002    POLYSIGNED offset = new_base - old_base + new_length - old_length;
2003    PolyWord *oldSp = this->taskSp;
2004    this->taskSp = oldSp + offset;
2005    this->hr    = this->hr + offset;
2006
2007    /* Skip the unused part of the stack. */
2008
2009    POLYUNSIGNED i = oldSp - old_base;
2010
2011    ASSERT (i <= old_length);
2012
2013    i = old_length - i;
2014
2015    PolyWord *old = oldSp;
2016    PolyWord *newp= this->taskSp;
2017
2018    while (i--)
2019    {
2020//        ASSERT(old >= old_base && old < old_base+old_length);
2021//        ASSERT(newp >= new_base && newp < new_base+new_length);
2022        PolyWord old_word = *old++;
2023        if (old_word.IsTagged() || old_word.AsStackAddr() < old_base || old_word.AsStackAddr() >= old_top)
2024            *newp++ = old_word;
2025        else
2026            *newp++ = PolyWord::FromStackAddr(old_word.AsStackAddr() + offset);
2027    }
2028    ASSERT(old == ((PolyWord*)old_stack)+old_length);
2029    ASSERT(newp == ((PolyWord*)new_stack)+new_length);
2030}
2031
2032Handle IntTaskData::EnterPolyCode()
2033/* Called from "main" to enter the code. */
2034{
2035    Handle hOriginal = this->saveVec.mark(); // Set this up for the IO calls.
2036    while (1)
2037    {
2038        this->saveVec.reset(hOriginal); // Remove old RTS arguments and results.
2039
2040        // Run the ML code and return with the function to call.
2041        this->inML = true;
2042        int ioFunction = SwitchToPoly();
2043        this->inML = false;
2044
2045        try {
2046            switch (ioFunction)
2047            {
2048            case -1:
2049                // We've been interrupted.  This usually involves simulating a
2050                // stack overflow so we could come here because of a genuine
2051                // stack overflow.
2052                // Previously this code was executed on every RTS call but there
2053                // were problems on Mac OS X at least with contention on schedLock.
2054                // Process any asynchronous events i.e. interrupts or kill
2055                processes->ProcessAsynchRequests(this);
2056                // Release and re-acquire use of the ML memory to allow another thread
2057                // to GC.
2058                processes->ThreadReleaseMLMemory(this);
2059                processes->ThreadUseMLMemory(this);
2060                break;
2061
2062            case -2: // A callback has returned.
2063                ASSERT(0); // Callbacks aren't implemented
2064
2065            default:
2066                Crash("Unknown io operation %d\n", ioFunction);
2067            }
2068        }
2069        catch (IOException &) {
2070        }
2071
2072    }
2073}
2074
2075// As far as possible we want locking and unlocking an ML mutex to be fast so
2076// we try to implement the code in the assembly code using appropriate
2077// interlocked instructions.  That does mean that if we need to lock and
2078// unlock an ML mutex in this code we have to use the same, machine-dependent,
2079// code to do it.  These are defaults that are used where there is no
2080// machine-specific code.
2081
2082static Handle ProcessAtomicIncrement(TaskData *taskData, Handle mutexp)
2083{
2084    PLocker l(&mutexLock);
2085    PolyObject *p = DEREFHANDLE(mutexp);
2086    // A thread can only call this once so the values will be short
2087    PolyWord newValue = TAGGED(UNTAGGED(p->Get(0))+1);
2088    p->Set(0, newValue);
2089    return taskData->saveVec.push(newValue);
2090}
2091
2092// Release a mutex.  We need to lock the mutex to ensure we don't
2093// reset it in the time between one of atomic operations reading
2094// and writing the mutex.
2095static Handle ProcessAtomicReset(TaskData *taskData, Handle mutexp)
2096{
2097    PLocker l(&mutexLock);
2098    DEREFHANDLE(mutexp)->Set(0, TAGGED(1)); // Set this to released.
2099    return taskData->saveVec.push(TAGGED(0)); // Push the unit result
2100}
2101
2102Handle IntTaskData::AtomicIncrement(Handle mutexp)
2103{
2104    return ProcessAtomicIncrement(this, mutexp);
2105}
2106
2107void IntTaskData::AtomicReset(Handle mutexp)
2108{
2109    (void)ProcessAtomicReset(this, mutexp);
2110}
2111
2112bool IntTaskData::AddTimeProfileCount(SIGNALCONTEXT *context)
2113{
2114    if (taskPc != 0)
2115    {
2116        // See if the PC we've got is an ML code address.
2117        MemSpace *space = gMem.SpaceForAddress(taskPc);
2118        if (space != 0 && (space->spaceType == ST_CODE || space->spaceType == ST_PERMANENT))
2119        {
2120            add_count(this, taskPc, 1);
2121            return true;
2122        }
2123    }
2124    return false;
2125}
2126
2127
2128static Interpreter interpreterObject;
2129
2130MachineDependent *machineDependent = &interpreterObject;
2131
2132// PolySetCodeConstant is not actually used in the interpreted version.
2133// It is used in the X86 code-generator to insert inline constants.
2134// Compat560 creates an RTS function unconditionally and rather than change
2135// that it's easier to add it here for the time being.
2136extern "C" {
2137    POLYEXTERNALSYMBOL POLYUNSIGNED PolySetCodeConstant(byte *pointer, PolyWord offset, PolyWord c, PolyWord flags);
2138}
2139
2140POLYUNSIGNED PolySetCodeConstant(byte *pointer, PolyWord offset, PolyWord c, PolyWord flags)
2141{
2142    return TAGGED(0).AsUnsigned();
2143}
2144
2145struct _entrypts machineSpecificEPT[] =
2146{
2147    { "PolySetCodeConstant",              (polyRTSFunction)&PolySetCodeConstant},
2148
2149    { NULL, NULL} // End of list.
2150};
2151