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