2 * The LittleSmalltalk byte code interpreter
4 * ---------------------------------------------------------------
5 * Little Smalltalk, Version 5
7 * Copyright (C) 1987-2005 by Timothy A. Budd
8 * Copyright (C) 2007 by Charles R. Childers
9 * Copyright (C) 2005-2007 by Danny Reinhold
10 * Copyright (C) 2010 by Ketmar // Invisible Vector
12 * ============================================================================
13 * This license applies to the virtual machine and to the initial image of
14 * the Little Smalltalk system and to all files in the Little Smalltalk
15 * packages except the files explicitly licensed with another license(s).
16 * ============================================================================
17 * Permission is hereby granted, free of charge, to any person obtaining a copy
18 * of this software and associated documentation files (the "Software"), to deal
19 * in the Software without restriction, including without limitation the rights
20 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 * copies of the Software, and to permit persons to whom the Software is
22 * furnished to do so, subject to the following conditions:
24 * The above copyright notice and this permission notice shall be included in
25 * all copies or substantial portions of the Software.
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 * DEALINGS IN THE SOFTWARE.
37 * bytecode interpreter module
39 * given a process object, execute bytecodes in a tight loop.
41 * performs subroutine calls for
42 * a) garbage collection
43 * b) finding a non-cached method
44 * c) executing a primitive
45 * d) creating an integer
47 * otherwise simply loops until time slice has ended
57 #include "primlib/lst_primitives.h"
61 lstObject
*lstPrimCtx
= NULL
;
66 #define COLLECT_METHOD_STATISTICS
69 #define MARKARG_INLINER_CHECK
70 #define INLINER_ACTIVE
72 #define INLINE_SOME_METHODS
79 // windoze msvcrt.dll is idiotic
82 # define PRINTF_LLD "%ld"
84 # define PRINTF_LLD "%lld"
87 # define PRINTF_LLD "%I64d"
90 #define BETTER_CACHE_CONTROL
92 LstEventCheckFn lstEventCheck
= NULL
;
94 int lstExecUserBreak
= 0;
96 unsigned int lstDebugFlag
= 0;
98 unsigned int lstInfoCacheHit
= 0;
99 unsigned int lstInfoCacheMiss
= 0;
101 unsigned int lstInfoLiteralHit
= 0;
102 unsigned int lstInfoIVarHit
= 0;
104 static int lstSuspended
= 0;
107 #define FNV_PRIME 16777619
108 #define FNV_OFFSET_BASIS 2166136261uL
111 static uint32_t fnvHash (const void *str
, int slen
) {
112 const unsigned char *buf
= (const unsigned char *)str
;
113 uint32_t acc
= FNV_OFFSET_BASIS
;
114 if (slen
> SIZE_TH
) {
115 int left
= slen
-SIZE_TH
;
116 if (left
> SIZE_TH
) left
= SIZE_TH
;
117 const unsigned char *buf1
= (const unsigned char *)str
;
118 buf1
= buf1
+slen
-left
;
119 while (slen
-- > 0) { acc
*= FNV_PRIME
; acc
^= *buf
++; }
120 while (left
-- > 0) { acc
*= FNV_PRIME
; acc
^= *buf1
++; }
122 while (slen
-- > 0) { acc
*= FNV_PRIME
; acc
^= *buf
++; }
128 static inline int LST_RSTACK_NSP (void) {
129 if (lstRootTop
>= LST_ROOTSTACK_LIMIT
) lstFatal("out of root stack", 0);
134 /* The following are roots for the file out */
135 lstObject
*lstNilObj
= NULL
;
136 lstObject
*lstTrueObj
= NULL
;
137 lstObject
*lstFalseObj
= NULL
;
138 lstObject
*lstBooleanClass
= NULL
;
139 lstObject
*lstSmallIntClass
= NULL
;
140 lstObject
*lstCharClass
= NULL
;
141 lstObject
*lstArrayClass
= NULL
;
142 lstObject
*lstBlockClass
= NULL
;
143 lstObject
*lstContextClass
= NULL
;
144 lstObject
*lstProcessClass
= NULL
;
145 lstObject
*lstStringClass
= NULL
;
146 lstObject
*lstSymbolClass
= NULL
;
147 lstObject
*lstByteArrayClass
= NULL
;
148 lstObject
*lstByteCodeClass
= NULL
;
149 lstObject
*lstMethodClass
= NULL
;
150 lstObject
*lstGlobalObj
= NULL
;
151 lstObject
*lstBinMsgs
[LST_MAX_BIN_MSG
] = { NULL
};
152 lstObject
*lstIntegerClass
= NULL
;
153 lstObject
*lstFloatClass
= NULL
;
154 lstObject
*lstNumberClass
= NULL
;
155 lstObject
*lstBadMethodSym
= NULL
;
156 lstObject
*lstInitMethod
= NULL
;
157 lstObject
*lstLoadMethod
= NULL
;
158 lstObject
*lstDoStrMethod
= NULL
;
159 lstObject
*lstReplMethod
= NULL
;
160 lstObject
*lstNewSymMethod
= NULL
;
161 lstObject
*lstSetGlobMethod
= NULL
;
164 #ifdef INLINE_SOME_METHODS
165 static lstObject
*lstMetaCharClass
= NULL
;
167 static lstObject
*lstArrayAtMethod
= NULL
;
168 static lstObject
*lstArraySizeMethod
= NULL
;
169 static lstObject
*lstMetaCharNewMethod
= NULL
;
170 static lstObject
*lstStringAtIfAbsentMethod
= NULL
;
171 static lstObject
*lstStringAtMethod
= NULL
;
172 static lstObject
*lstStringBasicAtPutMethod
= NULL
;
173 static lstObject
*lstStringPrintStringMethod
= NULL
;
174 static lstObject
*lstSymbolPrintStringMethod
= NULL
;
175 static lstObject
*lstBlockValue1Method
= NULL
;
182 } lstInlineMethodList
[] = {
183 {2, "at:", &lstArrayClass
, &lstArrayAtMethod
},
184 {1, "size", &lstArrayClass
, &lstArraySizeMethod
},
185 {2, "at:", &lstStringClass
, &lstStringAtMethod
},
186 {1, "printString", &lstStringClass
, &lstStringPrintStringMethod
},
187 {1, "printString", &lstSymbolClass
, &lstSymbolPrintStringMethod
},
188 {3, "basicAt:put:", &lstStringClass
, &lstStringBasicAtPutMethod
},
189 {2, "new:", &lstMetaCharClass
, &lstMetaCharNewMethod
},
190 {3, "at:ifAbsent:", &lstStringClass
, &lstStringAtIfAbsentMethod
},
191 {2, "value:", &lstBlockClass
, &lstBlockValue1Method
},
197 #define DBGCHAN stderr
203 static void indent (lstObject
*ctx
) {
204 /*static int oldlev = 0;*/
206 while (ctx
&& (ctx
!= lstNilObj
)) {
209 ctx
= ctx
->data
[lstIVpreviousContextInContext
];
211 /* this lets you use your editor's brace matching to match up opening and closing indentation levels */
215 for (x = lev; x < oldlev; ++x) fputc('}', DBGCHAN);
216 } else if (lev > oldlev) {
218 for (x = oldlev; x < lev; ++x) fputc('{', DBGCHAN);
225 # define PC (curIP-1)
226 # define DBG0(msg) if (lstDebugFlag) {indent(context); fprintf(DBGCHAN, "%d: %s\n", PC, msg);}
227 # define DBG1(msg, arg) if (lstDebugFlag) {indent(context); fprintf(DBGCHAN, "%d: %s %d\n", PC, msg, arg);}
228 # define DBG2(msg, arg, arg1) if (lstDebugFlag) {indent(context); fprintf(DBGCHAN, "%d: %s %d %d\n", PC, msg, arg, arg1);}
229 # define DBGS(msg, cl, sel) \
230 if (lstDebugFlag) { \
232 char clnm[1024], selnm[1024]; \
233 lstGetString(clnm, sizeof(clnm), (lstObject *) cl); \
234 lstGetString(selnm, sizeof(selnm), (lstObject *) sel); \
235 fprintf(DBGCHAN, "%d: %s %s %s\n", PC, msg, clnm, selnm); }
238 # define DBG1(msg, arg)
239 # define DBG2(msg, arg, arg1)
240 # define DBGS(msg, cl, sel)
245 # define dprintf(...) fprintf(DBGCHAN, __VA_ARGS__)
247 # define dprintf(...)
251 # define iprintf(...) fprintf(DBGCHAN, __VA_ARGS__)
253 # define iprintf(...)
257 static int symbolcomp (lstObject
*left
, lstObject
*right
) {
258 int leftsize
= LST_SIZE(left
);
259 int rightsize
= LST_SIZE(right
);
260 int minsize
= leftsize
;
262 if (rightsize
< minsize
) minsize
= rightsize
;
263 /* use faster comparison */
265 if ((i
= memcmp(lstBytePtr(left
), lstBytePtr(right
), minsize
))) return i
;
267 return leftsize
-rightsize
;
271 /* method lookup routine, used when cache miss occurs */
272 static lstObject
*lookupMethod (lstObject
*selector
, lstObject
*stclass
) {
273 lstObject
*dict
, *keys
, *vals
, *val
;
274 LstInt low
, high
, mid
;
275 /* scan upward through the class hierarchy */
276 for (; stclass
&& stclass
!= lstNilObj
; stclass
= stclass
->data
[lstIVparentClassInClass
]) {
277 /* consider the Dictionary of methods for this Class */
278 #if 0 & defined(DEBUG)
280 static char tb
[1024];
281 fprintf(stderr
, "st=%p; u=%p; sz=%d\n", stclass
, lstNilObj
, LST_SIZE(stclass
));
282 lstGetString(tb
, sizeof(tb
), stclass
->data
[lstIVnameInClass
]);
283 fprintf(stderr
, " [%s]\n", tb
);
286 #if !defined(NDEBUG) || defined(DEBUG)
287 if (LST_IS_SMALLINT(stclass
)) lstFatal("lookupMethod: looking in SmallInt instance", 0);
288 if (LST_IS_BYTES(stclass
)) lstFatal("lookupMethod: looking in binary object", 0);
289 if (LST_SIZE(stclass
) < lstClassSize
) lstFatal("lookupMethod: looking in non-class object", 0);
291 dict
= stclass
->data
[lstIVmethodsInClass
];
292 #if !defined(NDEBUG) || defined(DEBUG)
293 #define lstFatalX(msg, dummy) {\
294 fprintf(stderr, "ERROR: %s\n", msg);\
295 fprintf(stderr, "class: %s\n", lstGetStringPtr(stclass->data[lstIVnameInClass]));\
296 if (dict && !LST_IS_SMALLINT(dict)) {\
297 while (dict && dict != lstNilObj) {\
298 if (LST_IS_SMALLINT(dict)) { fprintf(stderr, "dict: number\n"); break; }\
299 if (LST_SIZE(dict) < lstClassSize) { fprintf(stderr, "dict: instance (%p)\n", dict); }\
301 fprintf(stderr, "dict: %s\n", lstGetStringPtr(dict->data[lstIVnameInClass]));\
304 dict = dict->stclass;\
307 /* *((char *)0) = 0; */\
308 lstFatal(msg, dummy);\
310 if (!dict
) lstFatalX("lookupMethod: NULL dictionary", 0);
311 if (LST_IS_SMALLINT(dict
)) lstFatalX("lookupMethod: SmallInt dictionary", 0);
312 if (dict
->stclass
!= lstFindGlobal("Dictionary")) lstFatalX("lookupMethod: method list is not a dictionary", 0);
314 keys
= dict
->data
[0];
316 high
= LST_SIZE(keys
);
317 /* do a binary search through its keys, which are Symbol's. */
320 val
= keys
->data
[mid
];
321 /* if we find the selector, return the method lstObject. */
322 if (val
== selector
) {
323 vals
= dict
->data
[1];
324 return vals
->data
[mid
];
326 /* otherwise continue the binary search */
327 if (symbolcomp(selector
, val
) < 0) high
= mid
; else low
= mid
+1;
330 /* sorry, couldn't find a method */
335 /* method cache for speeding method lookup */
336 /* why 703? we have two primes: 701, 709, 719; let's try 719 */
337 #define MTD_CACHE_SIZE 719
338 #define MTD_CACHE_EXTRA 4
339 #define MTD_BAD_HIT_MAX 16
344 int badHits
; /* after MTD_BAD_HIT_MAX this cache item will be cleared */
347 lstObject
*mConst
; /* constant for methods returning constant */
348 int ivarNum
; /* ivar number for methods returning ivar */
349 } cache
[MTD_CACHE_SIZE
+MTD_CACHE_EXTRA
];
352 /* flush dynamic methods when GC occurs */
353 void lstFlushMethodCache (void) {
354 memset(cache
, 0, sizeof(cache
));
359 typedef struct LstRunContext LstRunContext
;
360 struct LstRunContext
{
361 /* ticks and locks fields will be filled only on process suspension */
365 LstRunContext
*prev
; /* previous process in group */
368 typedef struct LstRunGroup LstRunGroup
;
370 LstRunGroup
*prev
; /* prev group */
371 LstRunGroup
*next
; /* next group */
372 LstRunContext
*group
; /* next group */
373 int ticks
; /* for the whole group; used on sheduling */
374 int ewait
; /* >0: normal process waiting for the event */
378 static LstRunContext
*rsFree
= NULL
; /*TODO: free when too many*/
379 static LstRunGroup
*runGroups
= NULL
; /* list of all process groups */
380 static LstRunGroup
*curGroup
= NULL
; /* current run group */
381 static int finGroupCount
= 0;
382 static int runOnlyFins
= 0;
384 /* allocate new run context in the current group */
385 static LstRunContext
*allocRunContext (void) {
386 LstRunContext
*res
= rsFree
;
390 res
= calloc(1, sizeof(LstRunContext
));
392 res
->prev
= curGroup
->group
;
393 curGroup
->group
= res
;
398 /* release top context in the current group; return previous one */
399 static LstRunContext
*releaseRunContext (void) {
400 LstRunContext
*c
= curGroup
->group
;
402 curGroup
->group
= c
->prev
;
406 return curGroup
->group
;
410 static void lstCreateFinalizePGroup (lstObject
*prc
) {
411 LstRunGroup
*g
= calloc(1, sizeof(LstRunGroup
)), *p
= curGroup
?curGroup
:runGroups
;
412 LstRunContext
*c
= calloc(1, sizeof(LstRunContext
));
415 p
->next
= g
; /* can't be first group anyway */
416 if (g
->next
) g
->next
->prev
= g
;
418 /* note that we can't allocate objects here, 'cause this thing will be called from inside GC */
419 c
->ticksLeft
= 10000;
427 * note that process locks locks all groups now;
428 * this MUST be changed: we have to use fine-grained locks,
429 * mutexes and other cool things
433 typedef struct LstEventHandler LstEventHandler
;
434 struct LstEventHandler
{
435 LstEventHandler
*next
;
436 /*lstObject *process;*/
440 static LstEventHandler
*ehList
= NULL
;
443 static LstRunGroup
*findEventHandler (int eid
) {
444 LstEventHandler
*cur
, *prev
;
445 for (cur
= ehList
, prev
= NULL
; cur
; prev
= cur
, cur
= cur
->next
) {
446 if (cur
->eid
== eid
) {
447 LstRunGroup
*grp
= cur
->grp
;
448 /* remove from the list */
449 if (prev
) prev
->next
= cur
->next
; else ehList
= cur
->next
;
458 static void addOneShotEventHandler (int eid
, LstRunGroup
*grp
) {
459 LstEventHandler
*cur
= calloc(1, sizeof(LstEventHandler
));
467 #include "lst_memory.c"
470 static int groupHasProcess (const LstRunGroup
*g
, const lstObject
*prc
) {
471 const LstRunContext
*c
;
472 for (c
= g
->group
; c
; c
= c
->prev
) if (c
->process
== prc
) return 1;
480 # define POPIT (stack->data[--stackTop])
481 # define PUSHIT(n) if (stackTop >= LST_SIZE(stack)) { lstBackTrace(context); lstFatal("method stack overflow", curIP); } else stack->data[stackTop++] = (n)
483 # define POPIT (stack->data[--stackTop])
484 # define PUSHIT(n) stack->data[stackTop++] = (n)
488 /* Code locations are extracted as VAL's */
489 #define VAL (bp[curIP] | (bp[curIP+1] << 8))
490 /*#define VALSIZE 2*/
493 #define XRETURN(value) { LST_LEAVE_BLOCK(); return (value); }
495 #define GET_BCODE_OP(ip) \
496 low = (high = bp[ip++])&0x0F; high >>= 4; \
497 if (high == lstBCExtended) { high = low; low = bp[ip++]; }
500 #define CALC_CACHE_HASH(sel, cls) \
501 (LstUInt)((intptr_t)(sel)+(intptr_t)(cls))%MTD_CACHE_SIZE;
503 int lstEvtCheckLeft
= 1000;
505 static int resetEvtCheckLeft
= 0;
506 void lstResetEvtCheckLeft (void) { resetEvtCheckLeft
= 1; }
508 static int lastFailedPrim
= 0;
509 static int lastCalledPrim
= 0;
511 static int lstExecuteInternal (lstObject
*aProcess
, int ticks
, int locked
) {
515 lstObject
*retValue
= lstNilObj
;
516 lstObject
*context
= NULL
;
517 lstObject
*method
= NULL
;
518 lstObject
*stack
= NULL
;
519 lstObject
*arguments
= NULL
;
520 lstObject
*temporaries
= NULL
;
521 lstObject
*instanceVariables
= NULL
;
522 lstObject
*literals
= NULL
;
523 lstObject
*ptemp
= NULL
;
524 lstObject
*ptemp1
= NULL
;
525 lstObject
*messageSelector
;
526 lstObject
*receiverClass
;
528 int lockCount
= locked
>0;
529 const unsigned char *bp
;
535 int evtCheckLeft
= lstEvtCheckLeft
;
536 int oTicks
= curGroup
->ticks
;
537 int wasRunInWaits
= 1;
538 int grpTicks
= 10000;
541 /* reload all the necessary vars from the current context */
542 void reloadFromCtx (void) {
543 method
= context
->data
[lstIVmethodInContext
];
544 stack
= context
->data
[lstIVstackInContext
];
545 temporaries
= context
->data
[lstIVtemporariesInContext
];
546 arguments
= context
->data
[lstIVargumentsInContext
];
547 literals
= method
->data
[lstIVliteralsInMethod
];
548 instanceVariables
= arguments
->data
[lstIVreceiverInArguments
];
549 curIP
= lstIntValue(context
->data
[lstIVbytePointerInContext
]);
550 stackTop
= lstIntValue(context
->data
[lstIVstackTopInContext
]);
553 /* reloca current group state */
554 void reloadFromGroup (void) {
555 LstRunContext
*rc
= curGroup
->group
; /* current context */
556 aProcess
= rc
->process
;
557 ticks
= rc
->ticksLeft
;
558 lockCount
= rc
->lockCount
;
559 context
= aProcess
->data
[lstIVcontextInProcess
];
561 if (curGroup
->ewait
> 0) { lockCount
= 0; evtCheckLeft
= 1; } /* force event query */
564 /* load new process to the current group */
565 int loadNewProcess (lstObject
*newProc
) {
566 if (!newProc
|| newProc
== lstNilObj
) return lstReturnError
;
567 if (newProc
->data
[lstIVrunningInProcess
] != lstNilObj
) return lstReturnError
; /* already running/suspended */
568 /* get current context information */
569 context
= newProc
->data
[lstIVcontextInProcess
];
570 if (!context
|| context
== lstNilObj
) return lstReturnError
; /* terminated */
571 method
= context
->data
[lstIVmethodInContext
];
572 if (!method
|| method
== lstNilObj
) return lstReturnError
; /* the thing that should not be */
575 newProc
->data
[lstIVrunningInProcess
] = lstTrueObj
;
576 /* now create new runnint context */
577 LstRunContext
*rc
= allocRunContext();
578 rc
->process
= newProc
;
579 rc
->lockCount
= lockCount
;
580 rc
->ticksLeft
= ticks
;
584 /* fix process and context info */
585 void saveCurrentProcess (void) {
586 if (!curGroup
->group
) return;
587 if (curGroup
->ewait
<= 0) {
588 aProcess
->data
[lstIVresultInProcess
] = lstNilObj
;
589 aProcess
->data
[lstIVcontextInProcess
] = context
;
590 if (context
!= lstNilObj
) {
591 context
->data
[lstIVbytePointerInContext
] = lstNewInt(curIP
);
592 context
->data
[lstIVstackTopInContext
] = lstNewInt(stackTop
);
593 LstRunContext
*rc
= curGroup
->group
; /* current context */
594 rc
->ticksLeft
= ticks
;
595 rc
->lockCount
= lockCount
;
600 /* switch to next group and reload it */
601 void nextGroup (int skipIt
) {
603 if (skipIt
&& curGroup
) { saveCurrentProcess(); curGroup
= curGroup
->next
; }
604 if (!curGroup
) curGroup
= runGroups
;
607 dprintf("rof: cg=%p\n", curGroup
);
608 for (f
= 2; f
> 0; --f
) {
610 while (curGroup
&& !curGroup
->group
) curGroup
= curGroup
->next
;
611 } while (curGroup
&& !curGroup
->finalizer
);
613 curGroup
= runGroups
;
615 if (!curGroup
) lstFatal("internal error in finalizing stage", 0);
616 dprintf("rof: found cg=%p\n", curGroup
);
617 dprintf("rof: ctx=%p\n", curGroup
->group
);
618 dprintf("rof: fin=%d\n", curGroup
->finalizer
);
619 dprintf("rof: fin left=%d\n", finGroupCount
);
620 if (curGroup
&& !curGroup
->group
) {
621 if (finGroupCount
> 0) lstFatal("internal error in finalizing stage", 1);
625 for (f
= 2; f
> 0; --f
) {
626 while (curGroup
&& curGroup
->ewait
) curGroup
= curGroup
->next
;
628 curGroup
= runGroups
;
630 if (!curGroup
) curGroup
= runGroups
;
635 /* curGroup can be NULL after returning */
636 /* result==NULL: trying to kill main group */
637 LstRunGroup
*removeCurrentGroup (void) {
638 if (curGroup
== runGroups
) return NULL
;
639 /* exclude from the list */
640 curGroup
->prev
->next
= curGroup
->next
; /* it's safe, 'cause we can't remove the first (main) group */
641 if (curGroup
->next
) curGroup
->next
->prev
= curGroup
->prev
;
642 LstRunGroup
*pg
= curGroup
;
643 if (!(curGroup
= curGroup
->next
)) curGroup
= runGroups
;
647 /* return from process */
648 /* on return: low is the result; tmp!=0: switched to suspended context */
649 int doReturn (int res
) {
651 saveCurrentProcess();
652 LstRunContext
*rc
= curGroup
->group
; /* current context */
653 /*saveCurrentProcess();*/
655 aProcess
->data
[lstIVrunningInProcess
] = lstNilObj
;
656 aProcess
->data
[lstIVresultInProcess
] = retValue
;
657 if (res
== lstReturnReturned
) aProcess
->data
[lstIVcontextInProcess
] = lstNilObj
;
658 if ((rc
= releaseRunContext())) {
660 aProcess
= rc
->process
;
662 tmp
= (curGroup
->ewait
!= 0);
663 return 0; /* ok, the show must go on */
665 /* group is out of bussines now; exit if this is the main group */
666 if (curGroup
== runGroups
) {
667 /* 'main group': so get out of here */
668 runGroups
->ticks
= oTicks
;
671 /* remove empty group */
672 if (curGroup
->finalizer
) --finGroupCount
;
674 LstRunGroup
*pg
= removeCurrentGroup();
677 tmp
= (curGroup
->ewait
!= 0);
679 dprintf("return-switched from %p to %p\n", pg
, curGroup
);
681 dprintf("ctx=%p; mth=%p; ip=%d; tmp=%d\n", context
, method
, curIP
, tmp
);
684 return 0; /* don't stop at the top */
688 lstExecUserBreak
= 0;
690 assert(runGroups
->group
== NULL
);
700 curGroup
= runGroups
; /* switch to 'main' */
701 runGroups
->ticks
= ticks
;
702 if (loadNewProcess(aProcess
) != 0) {
703 releaseRunContext(); /* drop dummy context */
704 curGroup
= NULL
; /* restore old group */
705 return lstReturnError
; /* barf */
716 LST_TEMP(temporaries
);
717 LST_TEMP(instanceVariables
);
725 if (curGroup
->ewait
< 0) {
726 /* new waiting process */
727 saveCurrentProcess();
728 curGroup
->ewait
= -curGroup
->ewait
;
729 /*dprintf("%p: suspend for %d: ip=%d; sp=%d\n", curGroup, curGroup->ewait, curIP, stackTop);*/
730 evtCheckLeft
= 1; lockCount
= 0;
734 if (finGroupCount
< 1) {
735 runOnlyFins
= finGroupCount
= 0;
736 XRETURN(lstReturnAPISuspended
);
738 if (!curGroup
->finalizer
) {
742 if (curGroup
->ewait
> 0) {
743 curGroup
->finalizer
= 0;
750 if (evtCheckLeft
> 0 && (--evtCheckLeft
== 0)) {
751 evtCheckLeft
= lstEvtCheckLeft
;
752 if (lstExecUserBreak
) {
753 /* C API break; get out of here */
754 saveCurrentProcess();
757 fprintf(stderr
, "FUCK! SUSPEND!\n");
758 if (curGroup
== runGroups
) fprintf(stderr
, "SUSPEND IN MAIN GROUP!\n");
760 XRETURN(lstReturnAPISuspended
);
764 if ((id
= lstEventCheck(&ticks
)) > 0) {
765 LstRunGroup
*grp
= findEventHandler(id
);
767 /* save current process */
768 if (curGroup
->ewait
== 0) saveCurrentProcess();
769 /* wake up suspended process */
770 /*dprintf("found process group for %d\n", id);*/
771 /* switch to this context */
772 assert(grp
->ewait
== id
);
773 grp
->ewait
= 0; /* not waiting anymore */
776 /*dprintf("%p: resume: ip=%d; sp=%d\n", curGroup, curIP, stackTop);*/
777 goto doAllAgain
; /* continue with the next bytecode */
781 /* other shedulers */
782 if (curGroup
->ewait
== 0) {
783 /* process group sheduling */
784 if (grpTicks
> 0 && (--grpTicks
== 0)) {
786 if (runGroups
->next
) {
787 dprintf("GRPSHEDULE!\n");
788 LstRunGroup
*og
= curGroup
;
790 if (og
!= curGroup
) goto doAllAgain
; /* go on with the new process */
793 /* if we're running against a CPU tick count, shedule execution when we expire the given number of ticks */
794 if (ticks
> 0 && (--ticks
== 0)) {
796 /* locked; no sheduling */
797 ticks
= 1; /* this will slow down the process, but locks shouldn't be held for the long time */
799 dprintf("TimeExpired: lockCount=%d\n", lockCount
);
800 int rr
= doReturn(lstReturnTimeExpired
);
802 if (tmp
|| retGSwitch
) goto doAllAgain
;
808 if (curGroup
->ewait
> 0) {
809 /* this process is in the wait state */
810 /*dprintf("process are waiting for: %d\n", curGroup->ewait);*/
811 LstRunGroup
*og
= curGroup
;
814 if (og
!= curGroup
) dprintf("switched from %p to %p\n", og
, curGroup
);
816 if (og
== curGroup
|| !wasRunInWaits
) {
817 /*dprintf(" releasing time slice\n");*/
818 usleep(1); /* release timeslice */
826 /* decode the instruction */
827 bp
= (const unsigned char *)lstBytePtr(method
->data
[lstIVbyteCodesInMethod
]);
831 case lstBCPushInstance
:
832 DBG1("PushInstance", low
);
833 PUSHIT(instanceVariables
->data
[low
]);
835 case lstBCPushArgument
:
836 DBG1("PushArgument", low
);
837 PUSHIT(arguments
->data
[low
]);
839 case lstBCPushTemporary
:
840 DBG1("PushTemporary", low
);
841 PUSHIT(temporaries
->data
[low
]);
843 case lstBCPushLiteral
:
844 DBG1("PushLiteral", low
);
845 PUSHIT(literals
->data
[low
]);
847 case lstBCPushConstant
:
850 DBG0("PushConstant nil");
854 DBG0("PushConstant true");
857 case lstBLFalseConst
:
858 DBG0("PushConstant false");
863 DBG1("PushConstant", low
);
864 PUSHIT(lstNewInt(low
));
868 case lstBCAssignInstance
:
869 DBG1("AssignInstance", low
);
870 /* don't pop stack, leave result there */
871 lstWriteBarrier(&instanceVariables
->data
[low
], stack
->data
[stackTop
-1]);
873 case lstBCAssignArgument
:
874 DBG1("AssignArgument", low
);
875 /* don't pop stack, leave result there */
876 arguments
->data
[low
] = stack
->data
[stackTop
-1];
878 case lstBCAssignTemporary
:
879 DBG1("AssignTemporary", low
);
880 /* don't pop stack, leave result there */
881 temporaries
->data
[low
] = stack
->data
[stackTop
-1];
883 case lstBCMarkArguments
:
884 DBG1("MarkArguments", low
);
885 #ifdef MARKARG_INLINER_CHECK
886 if (ticks
!= 1 && low
> 1 && low
<= 3) {
887 /* check if next opcode is SendMessage */
888 switch (bp
[curIP
]/16) {
889 case lstBCSendMessage
:
893 messageSelector
= literals
->data
[l0
];
894 receiverClass
= stack
->data
[stackTop
-low
];
895 /*iprintf("stackTop: %d; low: %d; rc: %p\n", stackTop, low, receiverClass);*/
896 receiverClass
= LST_CLASS(receiverClass
);
897 tmp
= CALC_CACHE_HASH(messageSelector
, receiverClass
);
898 if (cache
[tmp
].name
== messageSelector
&& cache
[tmp
].stclass
== receiverClass
) {
899 checkForInlineCacheHit
:
900 # ifdef INLINE_SOME_METHODS
901 { int f
; op
= cache
[tmp
].method
;
902 for (f
= 0; lstInlineMethodList
[f
].name
; ++f
) {
903 if (low
== lstInlineMethodList
[f
].argc
&& *(lstInlineMethodList
[f
].method
) == op
) {
904 op
= stack
->data
[stackTop
-low
]; /* self */
905 if (LST_IS_SMALLINT(op
)) break; /* invalid object */
907 case 0: /* Array>>at: */
908 /*fprintf(stderr, "Array>>at: hit!\n");*/
909 if (LST_IS_BYTES(op
)) break;
910 op1
= stack
->data
[stackTop
-1]; /* index */
911 if (LST_IS_SMALLINT(op1
)) {
912 l0
= lstIntValue(op1
)-1;
913 if (l0
< 0 || l0
>= LST_SIZE(op
)) break; /* out of range */
915 retValue
= op
->data
[l0
];
917 goto markArgsInlined
;
920 case 1: /* Array>>size */
921 /*fprintf(stderr, "Array>>size hit!\n");*/
924 retValue
= lstNewInt(l0
);
926 goto markArgsInlined
;
927 case 2: /* String>>at: */
928 if (!LST_IS_BYTES(op
)) break; /* not a string */
929 op1
= stack
->data
[stackTop
-1]; /* index */
930 if (LST_IS_SMALLINT(op1
)) {
931 l0
= lstIntValue(op1
)-1;
932 if (l0
< 0 || l0
>= LST_SIZE(op
)) break; /* out of range */
934 l0
= lstBytePtr(op
)[l0
];
935 retValue
= lstCharClass
->data
[lstIVcharsInMetaChar
]->data
[l0
];
937 goto markArgsInlined
;
940 case 3: /* String>>printString */
941 /*fprintf(stderr, "String>>printString hit!\n");*/
942 if (op
->stclass
== lstSymbolClass
) {
944 l0
= LST_SIZE(ptemp
);
945 retValue
= (lstObject
*)lstMemAllocBin(l0
);
946 retValue
->stclass
= lstStringClass
;
947 if (l0
> 0) memcpy(lstBytePtr(retValue
), lstBytePtr(ptemp
), l0
);
949 } else if (op
->stclass
== lstStringClass
) {
956 goto markArgsInlined
;
957 case 4: /* Symbol>>printString */
958 /*fprintf(stderr, "Symbol>>printString hit!\n");*/
959 if (op
->stclass
== lstSymbolClass
) {
961 l0
= LST_SIZE(ptemp
);
962 retValue
= (lstObject
*)lstMemAllocBin(l0
);
963 retValue
->stclass
= lstStringClass
;
964 if (l0
> 0) memcpy(lstBytePtr(retValue
), lstBytePtr(ptemp
), l0
);
966 } else if (op
->stclass
== lstStringClass
) {
971 goto markArgsInlined
;
972 case 5: /* String>>basicAt:put: */
973 /*fprintf(stderr, "String>>basicAt:put: hit!\n");*/
974 if (!LST_IS_BYTES(op
)) break; /* not a string */
975 op1
= stack
->data
[stackTop
-2]; /* index */
976 if (LST_IS_SMALLINT(op1
)) {
977 l0
= lstIntValue(op1
)-1;
978 if (l0
< 0 || l0
>= LST_SIZE(op
)) break; /* out of range */
979 op1
= stack
->data
[stackTop
-1]; /* value */
980 if (LST_IS_SMALLINT(op1
)) {
982 lstBytePtr(op
)[l0
] = lstIntValue(op1
);
985 goto markArgsInlined
;
989 case 6: /* MetaChar>>new: */
990 /*fprintf(stderr, "MetaChar>>new: hit!\n");*/
991 op1
= stack
->data
[stackTop
-1]; /* value */
992 if (LST_IS_SMALLINT(op1
)) {
993 l0
= lstIntValue(op1
);
994 if (l0
< 0 || l0
>= 257) break; /* out of range */
996 retValue
= lstCharClass
->data
[lstIVcharsInMetaChar
]->data
[l0
];
998 goto markArgsInlined
;
1001 case 7: /* String>>at:ifAbsent: */
1002 /*fprintf(stderr, "String>>at:ifAbsent: hit!\n");*/
1003 if (!LST_IS_BYTES(op
)) break; /* not a string */
1004 op1
= stack
->data
[stackTop
-2]; /* index */
1005 if (LST_IS_SMALLINT(op1
)) {
1006 l0
= lstIntValue(op1
)-1;
1007 if (l0
< 0 || l0
>= LST_SIZE(op
)) break; /* out of range */
1009 l0
= lstBytePtr(op
)[l0
];
1010 retValue
= lstCharClass
->data
[lstIVcharsInMetaChar
]->data
[l0
];
1012 goto markArgsInlined
;
1015 case 8: /* Block>>value: */
1016 /*fprintf(stderr, "Block>>value: hit!\n");*/
1018 /* swap argumnets */
1019 op1
= stack
->data
[stackTop
-1];
1020 stack
->data
[stackTop
-1] = op
;
1021 stack
->data
[stackTop
-2] = op1
;
1022 ptemp
= lstNilObj
; /* flag */
1023 context
->data
[lstIVbytePointerInContext
] = lstNewInt(curIP
);
1024 context
->data
[lstIVstackTopInContext
] = lstNewInt(stackTop
-2);
1025 goto doBlockInvocation
;
1027 fprintf(stderr
, "ready to inline: %s\n", lstInlineMethodList
[f
].name
);
1034 if (low
!= 1 && low
!= 2) goto markArgsNoInlining
;
1036 if (cache
[tmp
].analyzed
<= 0) break;
1037 /*stackTop -= low;*/ /* remove all args */
1038 /* do inline, omit argument array creation */
1040 cache
[tmp
].badHits
= 0;
1041 l0
= bp
[curIP
= l1
]; /* skip SendMessage */
1043 case lstBCDoSpecial
*16+lstBXStackReturn
:
1044 context
= context
->data
[lstIVpreviousContextInContext
];
1046 case lstBCDoSpecial
*16+lstBXBlockReturn
:
1047 context
= context
->data
[lstIVcreatingContextInBlock
]->data
[lstIVpreviousContextInContext
];
1053 # ifdef INLINE_SOME_METHODS
1055 if (l0
) goto doReturn2
;
1056 stack
->data
[stackTop
++] = retValue
;
1057 goto markArgsCompleteNoPush
;
1060 /* execute inline code */
1061 if ((l1
= cache
[tmp
].ivarNum
) >= 0) {
1062 /* instance variable */
1063 if (cache
[tmp
].analyzed
== 1) {
1064 iprintf("ANALYZER: pushing ivar %d\n", l1
);
1065 retValue
= stack
->data
[stackTop
-1]->data
[l1
];
1067 iprintf("ANALYZER: setting ivar %d\n", l1
);
1069 (retValue
= stack
->data
[stackTop
-2])->data
[l1
] = stack
->data
[stackTop
-1];
1070 --stackTop
; /* drop argument, return self */
1071 if (l0
) { ++lstInfoIVarHit
; goto doReturn2
; }
1072 goto markArgsCompleteNoPush
;
1077 iprintf("ANALYZER: pushing constant/literal\n");
1078 ++lstInfoLiteralHit
;
1079 retValue
= cache
[tmp
].mConst
;
1081 if (l0
) goto doReturn2
;
1082 stack
->data
[stackTop
-1] = retValue
;
1083 goto markArgsCompleteNoPush
;
1084 } else if (cache
[tmp
+1].name
== messageSelector
&& cache
[tmp
+1].stclass
== receiverClass
) {
1085 /*++cache[tmp++].badHits;*/
1087 goto checkForInlineCacheHit
;
1091 if (bp
[curIP
]%16 == lstBCSendMessage
) {
1094 goto checkForInline
;
1099 # ifdef INLINE_SOME_METHODS
1104 op
= lstMemAlloc(low
);
1105 op
->stclass
= lstArrayClass
;
1106 /* now load new argument array */
1107 while (--low
>= 0) op
->data
[low
] = POPIT
;
1109 markArgsCompleteNoPush
:
1111 case lstBCPushBlock
:
1113 /* create a block object; low is arg location; next word is goto value; next byte is argCount */
1116 tmp
= bp
[curIP
++]; /* argCount */
1117 ptemp
= lstNewArray(lstIntValue(method
->data
[lstIVstackSizeInMethod
]));
1118 op
= lstMemAlloc(lstBlockSize
);
1119 op
->stclass
= lstBlockClass
;
1120 /*op = lstAllocInstance(lstBlockSize, lstBlockClass);*/
1121 op
->data
[lstIVbytePointerInContext
] = op
->data
[lstIVstackTopInBlock
] = lstNewInt(0);
1122 op
->data
[lstIVpreviousContextInBlock
] = lstNilObj
;
1123 op
->data
[lstIVbytePointerInBlock
] = lstNewInt(curIP
);
1124 op
->data
[lstIVargumentLocationInBlock
] = lstNewInt(low
);
1125 op
->data
[lstIVstackInBlock
] = ptemp
;
1126 op
->data
[lstIVargCountInBlock
] = lstNewInt(tmp
);
1127 op
->data
[lstIVcreatingContextInBlock
] =
1128 context
->stclass
==lstBlockClass
? context
->data
[lstIVcreatingContextInBlock
] : context
;
1129 op
->data
[lstIVprocOwnerInBlock
] = aProcess
;
1130 op
->data
[lstIVmethodInBlock
] = method
;
1131 op
->data
[lstIVargumentsInBlock
] = arguments
;
1132 op
->data
[lstIVtemporariesInBlock
] = temporaries
;
1138 case lstBCSendUnary
: /* optimize certain unary messages */
1139 DBG1("SendUnary", low
);
1143 retValue
= op
==lstNilObj
? lstTrueObj
: lstFalseObj
;
1145 case 1: /* notNil */
1146 retValue
= op
==lstNilObj
? lstFalseObj
: lstTrueObj
;
1149 lstFatal("unimplemented SendUnary", low
);
1153 case lstBCSendBinary
: /* optimize certain binary messages */
1154 DBG1("SendBinary", low
);
1159 retValue
= ptemp
==ptemp1
? lstTrueObj
: lstFalseObj
;
1161 ptemp
= ptemp1
= NULL
;
1164 /* small integers */
1165 if (LST_IS_SMALLINT(ptemp
) && LST_IS_SMALLINT(ptemp1
)) {
1166 int i
= lstIntValue(ptemp
);
1167 int j
= lstIntValue(ptemp1
);
1170 retValue
= i
<j
? lstTrueObj
: lstFalseObj
;
1173 retValue
= i
<=j
? lstTrueObj
: lstFalseObj
;
1176 itmp
= (int64_t)i
+j
;
1177 retValue
= lstNewInteger(itmp
);
1180 itmp
= (int64_t)i
-j
;
1181 retValue
= lstNewInteger(itmp
);
1184 itmp
= (int64_t)i
*j
;
1185 retValue
= lstNewInteger(itmp
);
1188 if (j
== 0) goto binoptfailed
;
1189 retValue
= lstNewInt(i
/j
);
1192 if (j
== 0) goto binoptfailed
;
1193 retValue
= lstNewInt(i
%j
);
1196 retValue
= i
>j
? lstTrueObj
: lstFalseObj
;
1199 retValue
= i
>=j
? lstTrueObj
: lstFalseObj
;
1202 retValue
= i
!=j
? lstTrueObj
: lstFalseObj
;
1205 retValue
= i
==j
? lstTrueObj
: lstFalseObj
;
1207 default: goto binoptfailed
;
1210 ptemp
= ptemp1
= NULL
;
1214 if (LST_CLASS(ptemp
) == lstCharClass
&& LST_CLASS(ptemp1
) == lstCharClass
) {
1215 int i
= lstIntValue(ptemp
->data
[0]);
1216 int j
= lstIntValue(ptemp1
->data
[0]);
1219 retValue
= i
<j
? lstTrueObj
: lstFalseObj
;
1222 retValue
= i
<=j
? lstTrueObj
: lstFalseObj
;
1225 retValue
= i
>j
? lstTrueObj
: lstFalseObj
;
1228 retValue
= i
>=j
? lstTrueObj
: lstFalseObj
;
1231 retValue
= i
!=j
? lstTrueObj
: lstFalseObj
;
1234 retValue
= i
==j
? lstTrueObj
: lstFalseObj
;
1236 default: goto binoptfailed
;
1239 ptemp
= ptemp1
= NULL
;
1243 if (ptemp
== lstTrueObj
|| ptemp
== lstFalseObj
) {
1244 /* can only do operations that won't trigger garbage collection */
1247 retValue
= ptemp
==lstTrueObj
? ptemp1
: lstFalseObj
;
1250 retValue
= ptemp
==lstTrueObj
? lstTrueObj
: ptemp1
;
1256 ptemp
= ptemp1
= NULL
;
1260 if (ptemp
== lstNilObj
) {
1261 /* can only do operations that won't trigger garbage collection */
1264 retValue
= lstFalseObj
;
1273 ptemp
= ptemp1
= NULL
;
1276 /* logics, not bool, not nil */
1277 if (LST_IS_SMALLINT(ptemp
) || ptemp
->stclass
!= lstBooleanClass
) {
1289 ptemp
= ptemp1
= NULL
;
1293 if (LST_IS_BYTES(ptemp
) && LST_IS_BYTES(ptemp1
)) {
1296 retValue
= symbolcomp(ptemp
, ptemp1
)<0 ? lstTrueObj
: lstFalseObj
;
1299 retValue
= symbolcomp(ptemp
, ptemp1
)<=0 ? lstTrueObj
: lstFalseObj
;
1302 if (ptemp
->stclass
== ptemp1
->stclass
&&
1303 (ptemp
->stclass
== lstStringClass
|| ptemp
->stclass
== lstByteArrayClass
||
1304 ptemp
->stclass
== lstByteCodeClass
)) {
1305 /* string concatenation */
1306 retValue
= (lstObject
*)lstMemAllocBin(LST_SIZE(ptemp
)+LST_SIZE(ptemp1
));
1307 retValue
->stclass
= ptemp
->stclass
;
1308 tmp
= LST_SIZE(ptemp
);
1309 if (tmp
) memcpy(lstBytePtr(retValue
), lstBytePtr(ptemp
), tmp
);
1310 l0
= LST_SIZE(ptemp1
);
1311 if (l0
) memcpy(lstBytePtr(retValue
)+tmp
, lstBytePtr(ptemp1
), l0
);
1316 retValue
= symbolcomp(ptemp
, ptemp1
)>0 ? lstTrueObj
: lstFalseObj
;
1319 retValue
= symbolcomp(ptemp
, ptemp1
)>=0 ? lstTrueObj
: lstFalseObj
;
1322 retValue
= symbolcomp(ptemp
, ptemp1
)!=0 ? lstTrueObj
: lstFalseObj
;
1325 retValue
= symbolcomp(ptemp
, ptemp1
)==0 ? lstTrueObj
: lstFalseObj
;
1327 default: goto binoptfailed
;
1330 ptemp
= ptemp1
= NULL
;
1333 /* do message send */
1335 arguments
= lstMemAlloc(2);
1336 arguments
->stclass
= lstArrayClass
;
1337 /* now load new argument array */
1338 arguments
->data
[0] = ptemp
;
1339 arguments
->data
[1] = ptemp1
;
1340 /* now go send message */
1341 messageSelector
= lstBinMsgs
[low
];
1342 ptemp
= ptemp1
= NULL
;
1343 goto findMethodFromSymbol
;
1344 case lstBCSendMessage
:
1345 /*DBG1("SendMessage, literal", low);*/
1346 messageSelector
= literals
->data
[low
];
1348 findMethodFromSymbol
:
1349 /* see if we can optimize tail call */
1350 if (ticks
== 1) l0
= 0;
1352 switch (bp
[curIP
]) {
1353 case lstBCDoSpecial
*16+lstBXStackReturn
: l0
= 1; break;
1354 case lstBCDoSpecial
*16+lstBXBlockReturn
: l0
= 2; break;
1355 default: l0
= 0; break;
1358 findMethodFromSymbol1
:
1359 receiverClass
= LST_CLASS(arguments
->data
[lstIVreceiverInArguments
]);
1360 assert(LST_CLASS(messageSelector
) == lstSymbolClass
);
1361 DBGS("SendMessage", receiverClass
->data
[lstIVnameInClass
], messageSelector
);
1363 assert(LST_CLASS(messageSelector
) == lstSymbolClass
);
1366 char clnm
[256], selnm
[256];
1367 lstGetString(clnm
, sizeof(clnm
), (lstObject
*)LST_CLASS(receiverClass
)->data
[lstIVnameInClass
]);
1368 lstGetString(selnm
, sizeof(selnm
), (lstObject
*)messageSelector
);
1369 fprintf(stderr
, "%04d: searching: %s>>%s\n", PC
, clnm
, selnm
);
1372 tmp
= CALC_CACHE_HASH(messageSelector
, receiverClass
);
1373 /*tmp = (LstUInt)((intptr_t)messageSelector+(intptr_t)receiverClass)%MTD_CACHE_SIZE;*/
1374 if (cache
[tmp
].name
== messageSelector
&& cache
[tmp
].stclass
== receiverClass
) {
1376 } else if (cache
[tmp
+1].name
== messageSelector
&& cache
[tmp
+1].stclass
== receiverClass
) {
1377 ++cache
[tmp
++].badHits
;
1378 cacheHit
: method
= cache
[tmp
].method
;
1382 if (++cache
[tmp
].badHits
>= MTD_BAD_HIT_MAX
) cache
[tmp
].name
= NULL
; /* clear this cache item */
1383 if (++cache
[tmp
+1].badHits
>= MTD_BAD_HIT_MAX
) cache
[tmp
+1].name
= NULL
; /* clear this cache item */
1384 method
= lookupMethod(messageSelector
, receiverClass
);
1386 /* send 'doesNotUnderstand:args:' */
1387 if (messageSelector
== lstBadMethodSym
) lstFatal("doesNotUnderstand:args: missing", 0);
1388 /* we can reach this code only once */
1389 ptemp
= receiverClass
;
1390 ptemp1
= messageSelector
;
1391 op
= lstMemAlloc(3);
1392 op
->stclass
= lstArrayClass
;
1393 op
->data
[lstIVreceiverInArguments
] = arguments
->data
[lstIVreceiverInArguments
];
1394 op
->data
[1] = ptemp1
; /* selector */
1395 op
->data
[2] = arguments
;
1397 receiverClass
= ptemp
; /* restore selector */
1398 ptemp
= ptemp1
= NULL
;
1399 messageSelector
= lstBadMethodSym
;
1400 goto findMethodFromSymbol1
;
1402 if (cache
[tmp
].name
&& cache
[tmp
].badHits
<= MTD_BAD_HIT_MAX
/2) ++tmp
;
1403 /*if (cache[tmp].name) ++tmp;*/
1404 cache
[tmp
].name
= messageSelector
;
1405 cache
[tmp
].stclass
= receiverClass
;
1406 cache
[tmp
].method
= method
;
1407 cache
[tmp
].goodHits
= 0; /* perfectly good cache */
1408 /*cache[tmp].analyzed = (LST_SIZE(arguments) != 1) ? -1 : 0*/;
1409 #ifdef INLINER_ACTIVE
1410 if ((op
= method
->data
[lstIVoptimDoneInMethod
]) != lstNilObj
) {
1411 if (op
== lstFalseObj
) {
1412 cache
[tmp
].analyzed
= -1; /* should not be analyzed */
1414 cache
[tmp
].analyzed
= 1; /* already analyzed */
1415 if (LST_IS_SMALLINT(op
)) {
1417 int f
= lstIntValue(op
);
1419 cache
[tmp
].analyzed
= 2;
1421 iprintf("ANALYZER: already analyzed setter; ivar %d\n", f
);
1423 iprintf("ANALYZER: already analyzed; ivar %d\n", f
);
1425 cache
[tmp
].ivarNum
= f
;
1427 cache
[tmp
].mConst
= method
->data
[lstIVretResInMethod
];
1428 cache
[tmp
].ivarNum
= -1;
1429 iprintf("ANALYZER: already analyzed; constant\n");
1433 op
= method
->data
[lstIVargCountInMethod
];
1434 if (LST_IS_SMALLINT(op
) && (lstIntValue(op
) == 1 || lstIntValue(op
) == 2)) {
1435 iprintf("ANALYZER: to be analyzed (argc=%d)\n", lstIntValue(op
));
1436 cache
[tmp
].analyzed
= 0; /* analyze it in the future */
1438 iprintf("ANALYZER: never be analyzed; argc=%d\n", LST_IS_SMALLINT(op
) ? lstIntValue(op
) : -666);
1439 cache
[tmp
].analyzed
= -1; /* never */
1440 method
->data
[lstIVoptimDoneInMethod
] = lstFalseObj
; /* 'never' flag */
1445 cache
[tmp
].badHits
= 0; /* good cache */
1446 #ifdef INLINER_ACTIVE
1447 if (cache
[tmp
].analyzed
> 0) {
1449 if (ticks
== 1) goto analyzerJustDoIt
;
1452 case 1: context
= context
->data
[lstIVpreviousContextInContext
]; break;
1453 case 2: context
= context
->data
[lstIVcreatingContextInBlock
]->data
[lstIVpreviousContextInContext
]; break;
1454 default: l0
= 0; break;
1457 if ((l1
= cache
[tmp
].ivarNum
) >= 0) {
1458 /* instance variable */
1459 if (cache
[tmp
].analyzed
== 1) {
1460 iprintf("ANALYZER!: pushing ivar %d\n", l1
);
1461 retValue
= arguments
->data
[lstIVreceiverInArguments
]->data
[l1
];
1463 iprintf("ANALYZER!: setting ivar %d\n", l1
);
1464 assert(cache
[tmp
].analyzed
== 2);
1465 assert(LST_SIZE(arguments
) == 2);
1466 (retValue
= arguments
->data
[lstIVreceiverInArguments
])->data
[l1
] = arguments
->data
[1];
1471 iprintf("ANALYZER!: pushing constant/literal\n");
1472 retValue
= cache
[tmp
].mConst
;
1473 ++lstInfoLiteralHit
;
1475 /* restore changed vars */
1476 if (l0
) goto doReturn2
;
1477 method
= context
->data
[lstIVmethodInContext
];
1478 arguments
= context
->data
[lstIVargumentsInContext
];
1481 } else if (!cache
[tmp
].analyzed
) {
1482 if (++cache
[tmp
].goodHits
> 3) {
1483 /* analyze method */
1484 bp
= (const unsigned char *)lstBytePtr(method
->data
[lstIVbyteCodesInMethod
]);
1485 op
= method
->data
[lstIVargCountInMethod
];
1486 if (lstIntValue(op
) == 1) {
1489 case lstBCPushInstance
:
1490 if (bp
[1] != lstBCDoSpecial
*16+lstBXStackReturn
) goto analyzeFailed
;
1491 cache
[tmp
].ivarNum
= bp
[0]%16;
1493 case lstBCPushLiteral
:
1494 if (bp
[1] != lstBCDoSpecial
*16+lstBXStackReturn
) goto analyzeFailed
;
1495 cache
[tmp
].mConst
= method
->data
[lstIVliteralsInMethod
]->data
[bp
[0]%16];
1496 cache
[tmp
].ivarNum
= -1;
1498 case lstBCPushConstant
:
1499 if (bp
[1] != lstBCDoSpecial
*16+lstBXStackReturn
) goto analyzeFailed
;
1500 cache
[tmp
].ivarNum
= -1;
1502 case lstBLNilConst
: cache
[tmp
].mConst
= lstNilObj
; break;
1503 case lstBLTrueConst
: cache
[tmp
].mConst
= lstTrueObj
; break;
1504 case lstBLFalseConst
: cache
[tmp
].mConst
= lstFalseObj
; break;
1505 default: l1
= (bp
[0]%16)-3; cache
[tmp
].mConst
= lstNewInt(l1
); break;
1510 case lstBCPushInstance
:
1511 if (bp
[2] != lstBCDoSpecial
*16+lstBXStackReturn
) goto analyzeFailed
;
1512 cache
[tmp
].ivarNum
= bp
[1];
1514 case lstBCPushLiteral
:
1515 if (bp
[2] != lstBCDoSpecial
*16+lstBXStackReturn
) goto analyzeFailed
;
1516 cache
[tmp
].mConst
= method
->data
[lstIVliteralsInMethod
]->data
[bp
[1]];
1517 cache
[tmp
].ivarNum
= -1;
1519 case lstBCPushConstant
:
1520 if (bp
[2] != lstBCDoSpecial
*16+lstBXStackReturn
) goto analyzeFailed
;
1521 cache
[tmp
].ivarNum
= -1;
1523 case lstBLNilConst
: cache
[tmp
].mConst
= lstNilObj
; break;
1524 case lstBLTrueConst
: cache
[tmp
].mConst
= lstTrueObj
; break;
1525 case lstBLFalseConst
: cache
[tmp
].mConst
= lstFalseObj
; break;
1526 default: l1
= bp
[1]-3; cache
[tmp
].mConst
= lstNewInt(l1
); break;
1529 default: goto analyzeFailed
;
1532 default: goto analyzeFailed
;
1534 iprintf("ANALYZER: succeed; ivar=%d\n", cache
[tmp
].ivarNum
);
1535 cache
[tmp
].analyzed
= 1;
1537 assert(lstIntValue(op
) == 2);
1540 0000: PushArgument 1
1541 0001: AssignInstance n
1545 /*TODO: parse extended lstBCAssignInstance*/
1546 if (bp
[0] == lstBCPushArgument
*16+1 && bp
[1]/16 == lstBCAssignInstance
&&
1547 bp
[2] == lstBCDoSpecial
*16+lstBXPopTop
&& bp
[3] == lstBCDoSpecial
*16+lstBXSelfReturn
) {
1548 /*goto analyzeFailed;*/
1549 iprintf("ANALYZER: setter found; ivar=%d\n", bp
[1]%16);
1550 cache
[tmp
].analyzed
= 2;
1551 cache
[tmp
].ivarNum
= bp
[1]%16;
1556 /* setup method info, so we can omit analyze stage in future */
1557 if (cache
[tmp
].ivarNum
>= 0) {
1558 int f
= cache
[tmp
].ivarNum
;
1559 if (cache
[tmp
].analyzed
== 2) f
= -(f
+1);
1560 method
->data
[lstIVoptimDoneInMethod
] = lstNewInt(f
);
1562 method
->data
[lstIVoptimDoneInMethod
] = lstTrueObj
;
1563 method
->data
[lstIVretResInMethod
] = cache
[tmp
].mConst
;
1565 goto analyzeSucceed
;
1567 cache
[tmp
].analyzed
= -1;
1568 method
->data
[lstIVoptimDoneInMethod
] = lstFalseObj
;
1573 #ifdef COLLECT_METHOD_STATISTICS
1574 l1
= lstIntValue(method
->data
[lstIVinvokeCountInMethod
])+1;
1575 if (LST_64FITS_SMALLINT(l1
)) method
->data
[lstIVinvokeCountInMethod
] = lstNewInt(l1
);
1578 /* save current IP and SP */
1579 context
->data
[lstIVstackTopInContext
] = lstNewInt(stackTop
);
1580 context
->data
[lstIVbytePointerInContext
] = lstNewInt(curIP
);
1581 /*context->data[lstIVprocOwnerInContext] = aProcess;*/
1582 /* build environment for new context */
1583 low
= lstIntValue(method
->data
[lstIVtemporarySizeInMethod
]);
1584 stack
= lstNewArray(lstIntValue(method
->data
[lstIVstackSizeInMethod
]));
1585 temporaries
= low
>0 ? lstNewArray(low
) : lstNilObj
;
1586 /* build the new context */
1587 context
= lstMemAlloc(lstContextSize
);
1588 context
->stclass
= lstContextClass
;
1589 /*context = lstAllocInstance(lstContextSize, lstContextClass);*/
1590 /*context->data[lstIVpreviousContextInContext] = ptemp;*/
1593 context
->data
[lstIVpreviousContextInContext
] = ptemp
->data
[lstIVpreviousContextInContext
];
1596 context
->data
[lstIVpreviousContextInContext
] =
1597 ptemp
->data
[lstIVcreatingContextInBlock
]->data
[lstIVpreviousContextInContext
];
1600 context
->data
[lstIVpreviousContextInContext
] = ptemp
;
1604 context
->data
[lstIVprocOwnerInContext
] = aProcess
;
1605 context
->data
[lstIVtemporariesInContext
] = temporaries
;
1606 context
->data
[lstIVstackInContext
] = stack
;
1607 context
->data
[lstIVstackTopInContext
] =
1608 context
->data
[lstIVbytePointerInContext
] = lstNewInt(0);
1609 context
->data
[lstIVmethodInContext
] = method
;
1610 context
->data
[lstIVargumentsInContext
] = arguments
;
1611 literals
= method
->data
[lstIVliteralsInMethod
];
1612 instanceVariables
= arguments
->data
[lstIVreceiverInArguments
];
1615 /* now go execute new method */
1617 /* execute primitive */
1618 case lstBCDoPrimitive
:
1619 /* low is argument count; next byte is primitive number */
1620 high
= bp
[curIP
++]; /* primitive number */
1622 /*DBG2("DoPrimitive", high, low);*/
1624 const char *pn
= lstFindPrimitiveName(high
);
1626 sprintf(tmsg
, "DoPrimitive %s; argc=%d", pn
, low
);
1630 lastCalledPrim
= high
;
1632 case 1: /* NewObject class size */
1633 if (low
!= 2) goto failPrimitiveArgs
;
1634 op
= POPIT
; /* size */
1635 op1
= POPIT
; /* class */
1636 if (!LST_IS_SMALLINT(op
)) goto failPrimitive
;
1637 tmp
= lstIntValue(op
); /* size */
1638 if (tmp
< 0) goto failPrimitive
;
1639 retValue
= lstAllocInstance(tmp
, op1
);
1641 case 2: /* NewByteArray class size */
1642 if (low
!= 2) goto failPrimitiveArgs
;
1643 op
= POPIT
; /* size */
1644 op1
= POPIT
; /* class */
1645 if (!LST_IS_SMALLINT(op
)) goto failPrimitive
;
1646 tmp
= lstIntValue(op
); /* size */
1647 if (tmp
< 0) goto failPrimitive
;
1648 retValue
= (lstObject
*)lstMemAllocBin(tmp
);
1649 retValue
->stclass
= op1
;
1650 if (tmp
> 0) memset(lstBytePtr(retValue
), 0, tmp
);
1652 case 3: /* ObjectIdentity */
1653 if (low
!= 2) goto failPrimitiveArgs
;
1656 retValue
= op
==op1
? lstTrueObj
: lstFalseObj
;
1658 case 4: /* ObjectClass */
1659 if (low
!= 1) goto failPrimitiveArgs
;
1661 retValue
= LST_CLASS(op
);
1663 case 5: /* ObjectSize */
1664 if (low
!= 1) goto failPrimitiveArgs
;
1666 tmp
= LST_IS_SMALLINT(op
) ? 0 : LST_SIZE(op
); /* SmallInt has no size at all; it's ok */
1667 retValue
= lstNewInt(tmp
);
1669 case 6: /* Array#at: obj index */
1670 if (low
!= 2) goto failPrimitiveArgs
;
1671 op
= POPIT
; /* index */
1672 op1
= POPIT
; /* obj */
1673 if (!LST_IS_SMALLINT(op
) || LST_IS_SMALLINT(op1
) || LST_IS_BYTES(op1
)) goto failPrimitive
;
1674 tmp
= lstIntValue(op
)-1;
1676 if (tmp
< 0 || (LstUInt
)tmp
>= LST_SIZE(op1
)) goto failPrimitive
;
1677 if (LST_IS_SMALLINT(op1
) || LST_IS_BYTES(op1
)) goto failPrimitive
;
1678 retValue
= op1
->data
[tmp
];
1680 case 7: /* Array#at:put: value obj index */
1681 if (low
!= 3) goto failPrimitiveArgs
;
1682 op
= POPIT
; /* index */
1683 retValue
= POPIT
; /* obj */
1684 op1
= POPIT
; /* value */
1685 if (!LST_IS_SMALLINT(op
) || LST_IS_SMALLINT(retValue
) || LST_IS_BYTES(retValue
)) goto failPrimitive
;
1686 tmp
= lstIntValue(op
)-1;
1688 if (tmp
< 0 || (LstUInt
)tmp
>= LST_SIZE(retValue
)) goto failPrimitive
;
1689 if (LST_IS_SMALLINT(retValue
) || LST_IS_BYTES(retValue
)) goto failPrimitive
;
1690 lstWriteBarrier(&retValue
->data
[tmp
], op1
);
1692 case 8: /* String#at: */
1693 if (low
!= 2) goto failPrimitiveArgs
;
1694 op
= POPIT
; /* index */
1695 op1
= POPIT
; /* object */
1696 if (!LST_IS_SMALLINT(op
) || !LST_IS_BYTES_EX(op1
)) goto failPrimitive
;
1697 tmp
= lstIntValue(op
)-1;
1699 if (tmp
< 0 || (LstUInt
)tmp
>= LST_SIZE(op1
)) goto failPrimitive
;
1700 tmp
= lstBytePtr(op1
)[tmp
];
1701 retValue
= lstNewInt(tmp
);
1703 case 9: /* String#at:put: value obj index */
1704 if (low
!= 3) goto failPrimitiveArgs
;
1705 op
= POPIT
; /* index */
1706 retValue
= POPIT
; /* obj */
1707 op1
= POPIT
; /* value */
1708 if (!LST_IS_SMALLINT(op
) || !LST_IS_BYTES_EX(retValue
) || !LST_IS_SMALLINT(op1
)) goto failPrimitive
;
1709 tmp
= lstIntValue(op
)-1;
1711 if (tmp
< 0 || (LstUInt
)tmp
>= LST_SIZE(retValue
)) goto failPrimitive
;
1712 lstBytePtr(retValue
)[tmp
] = lstIntValue(op1
);
1714 case 10: /* String#clone: what class */
1715 if (low
!= 2) goto failPrimitiveArgs
;
1716 /*TODO: check args */
1717 ptemp
= POPIT
; /* class */
1718 ptemp1
= POPIT
; /* obj */
1719 if (!LST_IS_BYTES_EX(ptemp1
)) { ptemp
= ptemp1
= NULL
; goto failPrimitive
; }
1720 tmp
= LST_SIZE(ptemp1
);
1721 retValue
= (lstObject
*)lstMemAllocBin(tmp
);
1722 retValue
->stclass
= ptemp
;
1723 if (tmp
> 0) memcpy(lstBytePtr(retValue
), lstBytePtr(ptemp1
), tmp
);
1724 ptemp
= ptemp1
= NULL
;
1726 case 11: /* String#Position: aString from: pos; match substring in a string; return index of substring or nil */
1727 case 12: /* String#LastPosition: aString from: pos; match substring in a string; return index of substring or nil */
1728 if (low
!= 3) goto failPrimitiveArgs
;
1731 if (LST_IS_SMALLINT(op
)) tmp
= lstIntValue(op
);
1732 else if (op
->stclass
== lstIntegerClass
) tmp
= lstLIntValue(op
);
1733 else { stackTop
-= 2; goto failPrimitive
; }
1734 if (tmp
< 1) tmp
= 1;
1738 if (!LST_IS_BYTES_EX(op1
)) {
1740 if (LST_IS_SMALLINT(op1
)) {
1741 x
= lstIntValue(op1
);
1742 } else if (op1
->stclass
== lstCharClass
) {
1744 if (LST_IS_SMALLINT(op1
)) x
= lstIntValue(op1
);
1746 if (x
< 0 || x
> 255) { --stackTop
; goto failPrimitive
; }
1747 sbuf
[0] = x
; sbuf
[1] = '\0';
1752 if (!LST_IS_BYTES_EX(op
)) goto failPrimitive
;
1754 l1
= op1
? LST_SIZE(op1
) : strlen(sbuf
);
1755 /*FIXME: tmp can be too big and cause the overflow*/
1756 retValue
= lstNilObj
;
1757 if (tmp
>= l0
|| l0
< 1 || l1
< 1 || l1
> l0
-tmp
) {
1758 /* can't be found, do nothing */
1760 const unsigned char *s0
= lstBytePtr(op
);
1761 const unsigned char *s1
= op1
? (const unsigned char *)lstBytePtr(op1
) : (const unsigned char *)sbuf
;
1762 s0
+= tmp
; l0
-= tmp
;
1763 /*FIXME: this can be faster, especially for LastPosition; rewrite it! */
1764 for (; l0
>= l1
; l0
--, s0
++, tmp
++) {
1765 if (memcmp(s0
, s1
, l1
) == 0) {
1766 retValue
= lstNewInt(tmp
+1);
1767 if (high
== 11) break; /* early exit for Position */
1772 case 13: /* StringCopyFromTo */
1773 if (low
!= 3) goto failPrimitiveArgs
;
1776 if (LST_IS_SMALLINT(op
)) tmp
= lstIntValue(op
);
1777 else if (op
->stclass
== lstIntegerClass
) tmp
= lstLIntValue(op
);
1778 else if (op
->stclass
== lstFloatClass
) tmp
= lstFloatValue(op
);
1779 else { stackTop
-= 2; goto failPrimitive
; }
1780 if (tmp
< 1) { stackTop
-= 2; goto failPrimitive
; }
1783 if (LST_IS_SMALLINT(op
)) x
= lstIntValue(op
);
1784 else if (op
->stclass
== lstIntegerClass
) x
= lstLIntValue(op
);
1785 else if (op
->stclass
== lstFloatClass
) x
= lstFloatValue(op
);
1786 else { --stackTop
; goto failPrimitive
; }
1787 if (x
< 1) { --stackTop
; goto failPrimitive
; }
1790 if (!LST_IS_BYTES_EX(op
)) goto failPrimitive
;
1792 /*printf("size=%d; from=%d; to=%d\n", low, x, tmp);*/
1794 if (tmp
< x
|| x
>= low
) low
= 0;
1798 low
= tmp
<low
? tmp
: low
;
1801 retValue
= (lstObject
*)lstMemAllocBin(low
);
1803 retValue
->stclass
= op
->stclass
;
1804 /*printf("copying from %d, %d bytes\n", x, low);*/
1805 if (low
> 0) memcpy(lstBytePtr(retValue
), lstBytePtr(op
)+x
, low
);
1807 case 14: /* BulkObjectExchange */
1808 if (low
!= 2) goto failPrimitiveArgs
;
1810 if (op
->stclass
!= lstArrayClass
) { --stackTop
; goto failPrimitive
; }
1812 if (retValue
->stclass
!= lstArrayClass
) goto failPrimitive
;
1813 if (LST_SIZE(op
) != LST_SIZE(retValue
)) goto failPrimitive
;
1814 lstSwapObjects(op
, retValue
, LST_SIZE(op
));
1816 case 15: { /* replaceFrom:... */ /* <replaceFrom:to:with:startingAt: start stop replacement repStart self> */
1817 if (low
!= 5) goto failPrimitiveArgs
;
1818 /*TODO: check args */
1819 retValue
= POPIT
; /* object */
1820 lstObject
*tmpRepStart
= POPIT
; /* startingAt */
1821 lstObject
*tmpSrc
= POPIT
; /* with */
1822 lstObject
*tmpStop
= POPIT
; /* to */
1823 lstObject
*tmpStart
= POPIT
; /* from */
1824 if (lstBulkReplace(retValue
, tmpStart
, tmpStop
, tmpSrc
, tmpRepStart
)) goto failPrimitive
;
1827 case 16: /* BlockInvocation: (args)* block */
1828 if (ptemp
!= NULL
) abort();
1830 if (low
< 1) goto failPrimitiveArgs
;
1831 /* low holds number of arguments */
1832 op
= POPIT
; /* block */
1834 /*if (op->data[lstIVbytePointerInContext] != lstNilObj) fprintf(stderr, "CALLING ALREADY CALLED BLOCK!\n");*/
1835 if (LST_IS_SMALLINT(op
) || LST_IS_BYTES(op
)) goto failPrimitiveArgs
;
1836 if (op
->stclass
!= lstBlockClass
&& !lstIsKindOf(op
, lstBlockClass
)) goto failPrimitiveArgs
;
1837 /*if (op->stclass != lstBlockClass) { stackTop -= (low-1); goto failPrimitiveArgs; }*/
1838 /* put arguments in place */
1839 /* get arguments location (tmp) */
1840 op1
= op
->data
[lstIVargumentLocationInBlock
];
1841 if (!LST_IS_SMALLINT(op1
)) goto failPrimitiveArgs
;
1842 tmp
= lstIntValue(op1
);
1843 /* get max argument count (l0) */
1844 op1
= op
->data
[lstIVargCountInBlock
];
1845 if (!LST_IS_SMALLINT(op1
)) goto failPrimitiveArgs
;
1846 l0
= lstIntValue(op1
);
1847 /* setup arguments */
1848 temporaries
= op
->data
[lstIVtemporariesInBlock
];
1849 /* do not barf if there are too many args; just ignore */
1850 /*fprintf(stderr, "block: args=%d; passed=%d\n", l0, low);*/
1851 if (low
> l0
) { stackTop
-= (low
-l0
); low
= l0
; } /* drop extra args */
1852 for (l1
= low
; l1
< l0
; ++l1
) temporaries
->data
[tmp
+l1
] = lstNilObj
;
1853 while (--low
>= 0) temporaries
->data
[tmp
+low
] = POPIT
;
1854 for (; low
>= 0; --low
) temporaries
->data
[tmp
+low
] = POPIT
;
1856 op
->data
[lstIVpreviousContextInBlock
] = context
->data
[lstIVpreviousContextInContext
];
1859 op
->data
[lstIVpreviousContextInBlock
] = context
;
1861 context
= /*aProcess->data[lstIVcontextInProcess] =*/ op
;
1862 context
->data
[lstIVtemporariesInContext
] = temporaries
;
1865 curIP
= lstIntValue(context
->data
[lstIVbytePointerInBlock
]);
1868 case 17: /* flush method cache; invalidate cache for class */
1870 * <#FlushMethodCache>: flush everything
1871 * <#FlushMethodCache oldclass>: flush the cache for the given class
1872 * <#FlushMethodCache oldmethod true>: flush the cache for the given method
1874 #ifdef BETTER_CACHE_CONTROL
1876 case 1: /* for class */
1877 dprintf("FLUSHCLASSCACHE\n");
1878 op
= POPIT
; /* old class */
1879 for (l0
= MTD_CACHE_SIZE
+MTD_CACHE_EXTRA
-1; l0
>= 0; --l0
) {
1880 if (cache
[l0
].name
&& cache
[l0
].stclass
== op
) cache
[l0
].name
= NULL
;
1883 case 2: /* for method */
1884 dprintf("FLUSHMETHODCACHE\n");
1885 --stackTop
; /* drop flag */
1886 op
= POPIT
; /* old method */
1887 for (l0
= MTD_CACHE_SIZE
+MTD_CACHE_EXTRA
-1; l0
>= 0; --l0
) {
1888 if (cache
[l0
].name
&& cache
[l0
].method
== op
) cache
[l0
].name
= NULL
;
1892 dprintf("FLUSHCACHE\n");
1894 lstFlushMethodCache();
1898 /*if (low == 1 || low > 3) { stackTop -= low; low = 0; }*/
1900 lstFlushMethodCache();
1904 case 18: /* SmallIntToInteger */
1905 if (low
!= 1) goto failPrimitiveArgs
;
1907 if (LST_IS_SMALLINT(op
)) retValue
= lstNewLongInt(lstIntValue(op
));
1908 else if (op
->stclass
== lstIntegerClass
) retValue
= lstNewLongInt(lstLIntValue(op
));
1909 else goto failPrimitive
;
1911 case 19: /* NumberToFloat */
1912 if (low
!= 1) goto failPrimitiveArgs
;
1914 if (LST_IS_SMALLINT(op
)) retValue
= lstNewFloat(lstIntValue(op
));
1915 else if (op
->stclass
== lstIntegerClass
) retValue
= lstNewFloat(lstLIntValue(op
));
1916 else if (op
->stclass
== lstFloatClass
) retValue
= lstNewFloat(lstFloatValue(op
));
1917 else goto failPrimitive
;
1919 case 20: /* FloatToInteger */
1920 if (low
< 1 || low
> 2) goto failPrimitiveArgs
;
1921 op
= POPIT
; /* float */
1923 op1
= POPIT
; /* opcode */
1924 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
1925 if (!LST_IS_BYTES_EX(op
) || op
->stclass
!= lstFloatClass
) goto failPrimitive
;
1926 fop0
= lstFloatValue(op
);
1927 switch (lstIntValue(op1
)) {
1928 case 1: fop0
= trunc(fop0
); break;
1929 case 2: fop0
= round(fop0
); break;
1930 case 3: fop0
= floor(fop0
); break;
1931 case 4: fop0
= ceil(fop0
); break;
1932 default: goto failPrimitive
;
1935 retValue
= lstNewInteger(ll0
);
1937 if (LST_IS_SMALLINT(op
)) retValue
= lstNewLongInt(lstIntValue(op
));
1938 else if (op
->stclass
== lstIntegerClass
) retValue
= lstNewLongInt(lstLIntValue(op
));
1939 else if (op
->stclass
== lstFloatClass
) retValue
= lstNewLongInt((LstLInt
)lstFloatValue(op
));
1940 else goto failPrimitive
;
1943 case 21: /* IntegerToSmallInt (low order of Integer -> SmallInt) */
1944 if (low
!= 1) goto failPrimitiveArgs
;
1946 if (LST_IS_SMALLINT(op
)) ll0
= lstIntValue(op
);
1947 else if (op
->stclass
== lstIntegerClass
) ll0
= lstLIntValue(op
);
1948 else goto failPrimitive
;
1950 if (!LST_64FITS_SMALLINT(tmp
)) goto failPrimitive
;
1951 retValue
= lstNewInt(tmp
);
1953 case 22: /* IntegerToSmallIntTrunc */
1954 if (low
!= 1) goto failPrimitiveArgs
;
1956 if (LST_IS_SMALLINT(op
)) retValue
= op
;
1957 else if (op
->stclass
== lstIntegerClass
) {
1958 ll0
= lstLIntValue(op
);
1960 retValue
= lstNewInt(tmp
);
1961 } else if (op
->stclass
== lstFloatClass
) {
1962 ll0
= (LstLInt
)(lstFloatValue(op
));
1964 retValue
= lstNewInt(tmp
);
1965 } else goto failPrimitive
;
1968 case 23: /* bit2op: bitOr: bitAnd: bitXor: */
1969 if (low
!= 3) goto failPrimitiveArgs
;
1970 /* operation type */
1972 if (!LST_IS_SMALLINT(op
)) { stackTop
-= 2; goto failPrimitive
; }
1973 tmp
= lstIntValue(op
); /* operation */
1976 if (LST_IS_SMALLINT(op
)) ll1
= lstIntValue(op
);
1977 else if (op
->stclass
== lstIntegerClass
) ll1
= lstLIntValue(op
);
1978 else { --stackTop
; goto failPrimitive
; }
1981 if (LST_IS_SMALLINT(op
)) ll0
= lstIntValue(op
);
1982 else if (op
->stclass
== lstIntegerClass
) ll0
= lstLIntValue(op
);
1983 else goto failPrimitive
;
1985 case 0: ll0
= ll0
| ll1
; break;
1986 case 1: ll0
= ll0
& ll1
; break;
1987 case 2: ll0
= ll0
^ ll1
; break;
1988 default: goto failPrimitive
;
1990 retValue
= lstNewInteger(ll0
);
1992 case 24: /* bitNot */
1993 if (low
!= 1) goto failPrimitiveArgs
;
1995 if (LST_IS_SMALLINT(op
)) ll0
= lstIntValue(op
);
1996 else if (op
->stclass
== lstIntegerClass
) ll0
= lstLIntValue(op
);
1997 else goto failPrimitive
;
1998 retValue
= lstNewInteger(~ll0
);
2000 case 25: /* bitShift: */
2001 if (low
!= 2) goto failPrimitiveArgs
;
2004 if (!LST_IS_SMALLINT(op
)) { --stackTop
; goto failPrimitive
; }
2005 tmp
= lstIntValue(op
); /* shift count */
2008 if (LST_IS_SMALLINT(op
)) ll0
= lstIntValue(op
);
2009 else if (op
->stclass
== lstIntegerClass
) ll0
= lstLIntValue(op
);
2010 else goto failPrimitive
;
2012 /* negative means shift right */
2018 retValue
= lstNewInteger(ll0
);
2021 case 26: /* SmallIntAdd */
2022 case 27: /* SmallIntSub */
2023 case 28: /* SmallIntMul */
2024 case 29: /* SmallIntDiv */
2025 case 30: /* SmallIntMod */
2026 case 31: /* SmallIntLess */
2027 case 32: /* SmallLessEqu */
2028 case 33: /* SmallIntGreat */
2029 case 34: /* SmallIntGreatEqu */
2030 case 35: /* SmallIntEqu */
2031 case 36: /* SmallIntNotEqu */
2032 if (low
!= 2) goto failPrimitiveArgs
;
2035 if (!LST_IS_SMALLINT(op
) || !LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2036 l1
= lstIntValue(op1
);
2037 l0
= lstIntValue(op
);
2040 case 26: itmp
= (int64_t)l0
+l1
; retValue
= lstNewInteger(itmp
); break;
2041 case 27: itmp
= (int64_t)l0
-l1
; retValue
= lstNewInteger(itmp
); break;
2042 case 28: itmp
= (int64_t)l0
*l1
; retValue
= lstNewInteger(itmp
); break;
2043 case 29: if (l1
== 0) goto failPrimitive
; l0
/= l1
; retValue
= lstNewInt(l0
); break;
2044 case 30: if (l1
== 0) goto failPrimitive
; l0
%= l1
; retValue
= lstNewInt(l0
); break;
2048 case 31: retValue
= l0
<l1
? lstTrueObj
: lstFalseObj
; break;
2049 case 32: retValue
= l0
<=l1
? lstTrueObj
: lstFalseObj
; break;
2050 case 33: retValue
= l0
>l1
? lstTrueObj
: lstFalseObj
; break;
2051 case 34: retValue
= l0
>=l1
? lstTrueObj
: lstFalseObj
; break;
2052 case 35: retValue
= l0
==l1
? lstTrueObj
: lstFalseObj
; break;
2053 case 36: retValue
= l0
!=l1
? lstTrueObj
: lstFalseObj
; break;
2057 case 37: /* IntegerAdd */
2058 case 38: /* IntegerSub */
2059 case 39: /* IntegerMul */
2060 case 40: /* IntegerDiv */
2061 case 41: /* IntegerMod */
2062 case 42: /* IntegerLess */
2063 case 43: /* IntegerLessEqu */
2064 case 44: /* IntegerGreat */
2065 case 45: /* IntegerGreatEqu */
2066 case 46: /* IntegerEqu */
2067 case 47: /* IntegerNotEqu */
2068 if (low
!= 2) goto failPrimitiveArgs
;
2071 if (LST_IS_SMALLINT(op1
)) ll1
= lstIntValue(op1
);
2072 else if (op1
->stclass
== lstIntegerClass
) ll1
= lstLIntValue(op1
);
2073 else goto failPrimitive
;
2074 if (LST_IS_SMALLINT(op
)) ll0
= lstIntValue(op
);
2075 else if (op
->stclass
== lstIntegerClass
) ll0
= lstLIntValue(op
);
2076 else goto failPrimitive
;
2078 case 37: retValue
= lstNewLongInt(ll0
+ll1
); break;
2079 case 38: retValue
= lstNewLongInt(ll0
-ll1
); break;
2080 case 39: retValue
= lstNewLongInt(ll0
*ll1
); break;
2081 case 40: if (ll1
== 0) goto failPrimitive
; retValue
= lstNewLongInt(ll0
/ll1
); break;
2082 case 41: if (ll1
== 0) goto failPrimitive
; retValue
= lstNewLongInt(ll0
%ll1
); break;
2083 case 42: retValue
= ll0
<ll1
? lstTrueObj
: lstFalseObj
; break;
2084 case 43: retValue
= ll0
<=ll1
? lstTrueObj
: lstFalseObj
; break;
2085 case 44: retValue
= ll0
>ll1
? lstTrueObj
: lstFalseObj
; break;
2086 case 45: retValue
= ll0
>=ll1
? lstTrueObj
: lstFalseObj
; break;
2087 case 46: retValue
= ll0
==ll1
? lstTrueObj
: lstFalseObj
; break;
2088 case 47: retValue
= ll0
!=ll1
? lstTrueObj
: lstFalseObj
; break;
2091 case 48: /* FloatAdd */
2092 case 49: /* FloatSub */
2093 case 50: /* FloatMul */
2094 case 51: /* FloatDiv */
2095 case 52: /* FloatLess */
2096 case 53: /* FloatLessEqu */
2097 case 54: /* FloatGreat */
2098 case 55: /* FloatGreatEqu */
2099 case 56: /* FloatEqu */
2100 case 57: /* FloatNotEqu */
2101 if (low
!= 2) goto failPrimitiveArgs
;
2104 if (LST_IS_SMALLINT(op
)) fop1
= (LstFloat
)lstIntValue(op
);
2105 else if (op
->stclass
== lstIntegerClass
) fop1
= (LstFloat
)lstLIntValue(op
);
2106 else if (op
->stclass
== lstFloatClass
) fop1
= lstFloatValue(op
);
2107 else { --stackTop
; goto failPrimitive
; }
2110 if (LST_IS_SMALLINT(op
)) fop0
= (LstFloat
)lstIntValue(op
);
2111 else if (op
->stclass
== lstIntegerClass
) fop0
= (LstFloat
)lstLIntValue(op
);
2112 else if (op
->stclass
== lstFloatClass
) fop0
= lstFloatValue(op
);
2113 else goto failPrimitive
;
2115 case 48: retValue
= lstNewFloat(fop0
+fop1
); break;
2116 case 49: retValue
= lstNewFloat(fop0
-fop1
); break;
2117 case 50: retValue
= lstNewFloat(fop0
*fop1
); break;
2118 case 51: if (fop0
== 0.0) goto failPrimitive
; retValue
= lstNewFloat(fop0
/fop1
); break;
2119 case 52: retValue
= fop0
<fop1
? lstTrueObj
: lstFalseObj
; break;
2120 case 53: retValue
= fop0
<=fop1
? lstTrueObj
: lstFalseObj
; break;
2121 case 54: retValue
= fop0
>fop1
? lstTrueObj
: lstFalseObj
; break;
2122 case 55: retValue
= fop0
>=fop1
? lstTrueObj
: lstFalseObj
; break;
2123 case 56: retValue
= fop0
==fop1
? lstTrueObj
: lstFalseObj
; break;
2124 case 57: retValue
= fop0
!=fop1
? lstTrueObj
: lstFalseObj
; break;
2127 case 58: /* FloatToString */
2128 if (low
!= 1) goto failPrimitiveArgs
;
2130 if (LST_IS_SMALLINT(op
)) sprintf(sbuf
, "%d", lstIntValue(op
));
2131 else if (op
->stclass
== lstIntegerClass
) sprintf(sbuf
, PRINTF_LLD
, lstLIntValue(op
));
2132 else if (op
->stclass
== lstFloatClass
) sprintf(sbuf
, "%.15g", lstFloatValue(op
));
2133 else goto failPrimitive
;
2134 retValue
= lstNewString(sbuf
);
2136 case 59: /* FloatNegate */
2137 if (low
!= 1) goto failPrimitiveArgs
;
2139 if (LST_IS_SMALLINT(op
)) fop0
= lstIntValue(op
);
2140 else if (op
->stclass
== lstIntegerClass
) fop0
= lstLIntValue(op
);
2141 else if (op
->stclass
== lstFloatClass
) fop0
= lstFloatValue(op
);
2142 else goto failPrimitive
;
2143 retValue
= lstNewFloat(-fop0
);
2146 case 60: /* PrimIdxName op arg */
2147 if (low
!= 2) goto failPrimitiveArgs
;
2148 op
= POPIT
; /* arg */
2149 op1
= POPIT
; /* opno */
2150 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2151 tmp
= lstIntValue(op1
);
2153 case 0: /* index by name */
2154 if (op
->stclass
!= lstStringClass
&& op
->stclass
!= lstSymbolClass
) goto failPrimitive
;
2155 if (LST_SIZE(op
) > 126) {
2156 retValue
= lstNilObj
;
2158 lstGetString(sbuf
, 256, op
);
2159 int ix
= lstFindPrimitiveIdx(sbuf
);
2160 retValue
= ix
>=0 ? lstNewInt(ix
) : lstNilObj
;
2163 case 1: /* name by index */
2164 if (LST_IS_SMALLINT(op
)) tmp
= lstIntValue(op
);
2165 else if (op
== lstIntegerClass
) tmp
= lstLIntValue(op
);
2166 else goto failPrimitive
;
2168 const char *n
= lstFindPrimitiveName(tmp
);
2169 retValue
= n
? lstNewString(n
) : lstNilObj
;
2172 default: goto failPrimitive
;
2176 case 61: /* GetCurrentProcess */
2177 if (low
!= 0) goto failPrimitiveArgs
;
2178 retValue
= aProcess
;
2181 case 62: /* error trap / yield -- halt process; no args: error; else: suspend (yield) */
2182 if (low
> 1) goto failPrimitiveArgs
;
2186 stackTop
-= (low
-1); /* drop other args */
2187 tmp
= lstReturnYield
; /* no-error flag */
2190 retValue
= lstNilObj
;
2191 tmp
= lstReturnError
; /* error flag */
2193 int rr
= doReturn(tmp
);
2194 if (rr
) XRETURN(rr
);
2195 if (tmp
|| retGSwitch
) goto doAllAgain
;
2198 case 63: /* ExecuteNewProcessAndWait proc tics */
2199 if (low
!= 2) goto failPrimitiveArgs
;
2200 op1
= POPIT
; /* ticks */
2201 op
= POPIT
; /* new process */
2202 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2203 if (!lstIsKindOf(op
, lstProcessClass
)) goto failPrimitive
;
2204 tmp
= lstIntValue(op1
);
2205 saveCurrentProcess();
2206 if (loadNewProcess(op
) == 0) {
2207 /* new process succesfully loaded */
2208 ticks
= tmp
<1 ? 0 : tmp
;
2209 lockCount
= lockCount
>0; /* start locked if locked */
2210 goto doAllAgain
; /* go on with the new process */
2212 reloadFromGroup(); /* restore old process */
2214 low
= lstReturnError
;
2215 execComplete
: /* low is the result */
2216 retValue
= lstNewInt(low
);
2219 case 64: /* LockUnlockSheduler */
2220 if (low
> 1) goto failPrimitiveArgs
;
2223 stackTop
-= (low
-1); /* drop other args */
2224 if (op
== lstFalseObj
) {
2226 if (--lockCount
< 0) {
2228 /*goto failPrimitive;*/
2235 /* query lock state */
2236 retValue
= lockCount
? lstTrueObj
: lstFalseObj
;
2238 case 65: /* TicksGetSet */
2239 if (low
> 1) goto failPrimitiveArgs
;
2242 stackTop
-= (low
-1); /* drop other args */
2243 if (LST_IS_SMALLINT(op
)) tmp
= lstIntValue(op
);
2244 else if (op
== lstIntegerClass
) tmp
= lstLIntValue(op
);
2245 else goto failPrimitive
;
2246 if (tmp
< 1) tmp
= 1;
2249 retValue
= LST_FITS_SMALLINT(ticks
) ? lstNewInt(ticks
) : lstNewLongInt(ticks
);
2251 case 66: /* RunGC */
2252 if (low
!= 0) goto failPrimitiveArgs
;
2254 retValue
= lstNilObj
;
2256 case 67: /* UserBreakSignal */
2257 if (low
!= 0) goto failPrimitiveArgs
;
2259 retValue
= lstNilObj
;
2261 case 68: /* EventHandlerCtl */
2265 if (low
!= 2) goto failPrimitiveArgs
;
2267 * <EventHandlerCtl eid true> -- suspend this process; wait for the event
2271 if (!LST_IS_SMALLINT(op
)) goto failPrimitive
;
2272 tmp
= lstIntValue(op
);
2273 if (tmp
< 1 || tmp
> 65535) goto failPrimitive
;
2274 if (op1
!= lstTrueObj
) goto failPrimitive
;
2275 /*dprintf("eventWaitFor: %d\n", tmp);*/
2276 addOneShotEventHandler(tmp
, curGroup
);
2277 curGroup
->ewait
= -tmp
; /* sheduler will save and skip this process */
2279 retValue
= lstTrueObj
;
2281 case 69: /* ProcessGroupCtl */
2283 * <ProcessGroupCtl 0 process [ticks]> -- create new process group
2285 if (low
< 2 || low
> 3) goto failPrimitiveArgs
;
2288 if (!LST_IS_SMALLINT(op
)) goto failPrimitiveArgs
;
2289 tmp
= lstIntValue(op
);
2290 if (tmp
< 1) tmp
= 10000;
2294 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2295 if (lstIntValue(op1
) != 0) goto failPrimitive
;
2296 if (!lstIsKindOf(op
, lstProcessClass
)) goto failPrimitive
;
2297 if (op
->data
[lstIVrunningInProcess
] != lstNilObj
) goto failPrimitive
;
2299 saveCurrentProcess();
2300 /* create new process group */
2301 LstRunGroup
*ng
= calloc(1, sizeof(LstRunGroup
)); /*TODO: reuse free groups*/
2302 LstRunGroup
*pg
= curGroup
;
2306 if (loadNewProcess(op
) == 0) {
2307 /* new process succesfully loaded, insert group in list (after current) */
2308 /*fprintf(stderr, "OK!\n");*/
2309 saveCurrentProcess();
2311 ng
->next
= pg
->next
;
2313 if (ng
->next
) ng
->next
->prev
= ng
;
2315 /* remove this group */
2319 /* restore old process */
2322 if (!ng
) goto failPrimitive
;
2326 case 70: /* PrintObject */
2330 if (low
> 2) goto failPrimitiveArgs
;
2331 op1
= low
==2 ? POPIT
: lstNilObj
;
2333 if (LST_IS_SMALLINT(op
)) {
2334 tmp
= lstIntValue(op
);
2335 if (tmp
>= 0 && tmp
<= 255) fputc(tmp
, stdout
);
2336 } else if (LST_IS_BYTES(op
)) {
2337 fwrite(lstBytePtr(op
), LST_SIZE(op
), 1, stdout
);
2338 } else if (op
->stclass
== lstCharClass
) {
2340 if (!LST_IS_SMALLINT(op
)) goto failPrimitive
;
2341 tmp
= lstIntValue(op
);
2342 if (tmp
>= 0 && tmp
<= 255) fputc(tmp
, stdout
);
2343 } else goto failPrimitive
;
2344 if (op1
!= lstNilObj
) fputc('\n', stdout
);
2346 retValue
= lstNilObj
;
2348 case 71: /* ReadCharacter */
2349 if (low
!= 0) goto failPrimitiveArgs
;
2351 retValue
= tmp
==EOF
? lstNilObj
: lstNewInt((int)(((unsigned int)tmp
)&0xff));
2354 case 72: /* FloatBAIO opcode num */
2355 if (low
!= 2) goto failPrimitiveArgs
;
2356 op
= POPIT
; /* num */
2357 op1
= POPIT
; /* opcode */
2358 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2359 tmp
= lstIntValue(op1
);
2360 if (tmp
< 0 || tmp
> 1) goto failPrimitive
;
2363 if (LST_CLASS(op
) != lstFloatClass
) goto failPrimitive
;
2365 retValue
= lstNewBinary(lstBytePtr(ptemp
), sizeof(LstFloat
));
2368 /* from byte array */
2370 if (LST_CLASS(op
) != lstByteArrayClass
) goto failPrimitive
;
2371 if (LST_SIZE(op
) != sizeof(n
)) goto failPrimitive
;
2372 memcpy(&n
, lstBytePtr(op
), sizeof(n
));
2373 retValue
= lstNewFloat(n
);
2376 case 73: /* IntegerBAIO opcode num */
2377 if (low
!= 2) goto failPrimitiveArgs
;
2378 op
= POPIT
; /* num */
2379 op1
= POPIT
; /* opcode */
2380 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2381 tmp
= lstIntValue(op1
);
2382 if (tmp
< 0 || tmp
> 1) goto failPrimitive
;
2385 if (LST_CLASS(op
) != lstIntegerClass
) goto failPrimitive
;
2387 retValue
= lstNewBinary(lstBytePtr(ptemp
), sizeof(LstLInt
));
2390 /* from byte array */
2392 if (LST_CLASS(op
) != lstByteArrayClass
) goto failPrimitive
;
2393 if (LST_SIZE(op
) != sizeof(n
)) goto failPrimitive
;
2394 memcpy(&n
, lstBytePtr(op
), sizeof(n
));
2395 retValue
= lstNewLongInt(n
);
2399 case 74: /* ExecuteContext ctx */
2400 if (low
!= 1) goto failPrimitiveArgs
;
2401 op
= POPIT
; /* ctx */
2402 if (LST_CLASS(op
) != lstContextClass
&& !lstIsKindOf(op
, lstContextClass
)) goto failPrimitive
;
2403 op
->data
[lstIVpreviousContextInContext
] = context
->data
[lstIVpreviousContextInContext
];
2408 case 75: /* StFinalizeCtl obj add-remove-flag */
2409 if (low
!= 2) goto failPrimitiveArgs
;
2410 op1
= POPIT
; /* flag */
2411 op
= POPIT
; /* object */
2412 if (LST_IS_SMALLINT(op
)) goto failPrimitive
; /* SmallInt can't have finalizer */
2413 if (op1
== lstNilObj
|| op1
== lstFalseObj
) {
2414 /* remove from list */
2415 if (LST_IS_STFIN(op
)) {
2416 LST_RESET_STFIN(op
);
2417 lstRemoveFromFList(&stFinListHead
, op
->fin
);
2422 if (!LST_IS_STFIN(op
)) {
2423 if (op
->fin
) goto failPrimitive
; /* object can have either C or ST finalizer, but not both */
2424 op
->fin
= calloc(1, sizeof(LstFinLink
));
2425 if (!op
->fin
) lstFatal("out of memory is StFinalizeCtl", 0x29a);
2427 op
->fin
->obj
= op
; /* owner */
2428 lstAddToFList(&stFinListHead
, op
->fin
);
2431 retValue
= lstNilObj
;
2434 case 76: /* StWeakCtl obj */
2435 if (low
!= 1) goto failPrimitiveArgs
;
2436 op
= POPIT
; /* object */
2437 if (LST_IS_SMALLINT(op
)) goto failPrimitive
; /* SmallInt can't have finalizer */
2439 if (!LST_IS_WEAK(op
)) {
2440 if (op
->fin
) goto failPrimitive
; /* object can have either C or ST finalizer, or marked as weak, but not all */
2441 op
->fin
= calloc(1, sizeof(LstFinLink
));
2442 if (!op
->fin
) lstFatal("out of memory is StWeakCtl", 0x29a);
2444 op
->fin
->obj
= op
; /* owner */
2445 lstAddToFList(&stWeakListHead
, op
->fin
);
2447 retValue
= lstNilObj
;
2450 case 77: /* FloatFunc float idx */
2451 if (low
!= 2) goto failPrimitiveArgs
;
2452 op1
= POPIT
; /* idx */
2453 op
= POPIT
; /* float */
2454 if (!LST_IS_SMALLINT(op1
)) goto failPrimitive
;
2455 tmp
= lstIntValue(op1
);
2456 if (LST_IS_SMALLINT(op
)) fop0
= lstIntValue(op
);
2457 else if (op
->stclass
== lstIntegerClass
) fop0
= lstLIntValue(op
);
2458 else if (op
->stclass
== lstFloatClass
) fop0
= lstFloatValue(op
);
2459 else goto failPrimitive
;
2461 case 0: fop0
= log2(fop0
); break;
2462 default: goto failPrimitive
;
2464 retValue
= lstNewFloat(fop0
);
2467 case 78: /* LastFailedPrim */
2469 retValue
= lstNewInt(lastFailedPrim
);
2472 case 79: {/* FNVHash byteobj */
2474 if (low
!= 1) goto failPrimitiveArgs
;
2475 op
= POPIT
; /* obj */
2476 if (!LST_IS_BYTES_EX(op
)) goto failPrimitive
;
2477 h
= fnvHash(lstBytePtr(op
), LST_SIZE(op
));
2478 tmp
= (h
%(INT_MAX
/2));
2479 retValue
= lstNewInt(tmp
);
2483 /* save stack pointers */
2488 lstPrimCtx
= context
;
2489 saveCurrentProcess();
2491 resetEvtCheckLeft
= 0;
2492 LSTPrimitiveFn pfn
= lstFindExtPrimitiveFn(high
);
2493 retValue
= pfn
? pfn(high
, &(stack
->data
[stackTop
-low
]), low
) : NULL
;
2494 if (resetEvtCheckLeft
) { evtCheckLeft
= 1; }
2496 stackTop
-= low
; /* remove primitive args */
2497 /* restore stacks */
2498 if (lstRootTop
< l0
) lstFatal("root stack error in primitive", high
);
2499 if (lstTempSP
< l1
) lstFatal("temp stack error in primitive", high
);
2502 if (!retValue
) goto failPrimitive
;
2505 /* force a stack return due to successful primitive */
2511 lastFailedPrim
= lastCalledPrim
;
2512 /* supply a return value for the failed primitive */
2515 /* done with primitive, continue execution loop */
2519 case lstBCDoSpecial
:
2521 case lstBXSelfReturn
:
2522 DBG0("DoSpecial: SelfReturn");
2523 retValue
= arguments
->data
[lstIVreceiverInArguments
];
2525 case lstBXStackReturn
:
2526 DBG0("DoSpecial: StackReturn");
2528 doReturn
: /*context->data[lstIVbytePointerInContext] = lstNilObj;*/
2529 context
= context
->data
[lstIVpreviousContextInContext
];
2530 doReturn2
: if (context
== lstNilObj
) {
2531 /*aProcess->data[lstIVcontextInProcess] = lstNilObj;*/ /* 'complete' flag */
2532 int rr
= doReturn(lstReturnReturned
);
2533 if (rr
) XRETURN(rr
);
2534 if (tmp
|| retGSwitch
) goto doAllAgain
;
2537 doReturn3
: aProcess
->data
[lstIVcontextInProcess
] = context
;
2541 case lstBXBlockReturn
:
2542 DBG0("DoSpecial: BlockReturn");
2543 /* the very bad thing is that this can be inter-group return */
2545 /*context->data[lstIVbytePointerInContext] = lstNilObj;*/
2546 /*dprintf("cp=%p\n", aProcess);*/
2547 context
= context
->data
[lstIVcreatingContextInBlock
]->data
[lstIVpreviousContextInContext
];
2548 if (context
== lstNilObj
) {
2549 if (curGroup
->group
->prev
) {
2550 /* not the last process */
2553 /* return from the process of the group */
2554 /* if this is return from the main group, we have to return from executor */
2555 if (curGroup
== runGroups
) {
2556 aProcess
= runGroups
->group
->process
; /* initial process */
2557 aProcess
->data
[lstIVresultInProcess
] = retValue
;
2558 aProcess
->data
[lstIVcontextInProcess
] = lstNilObj
;
2559 /* clear the current run group */
2560 while (curGroup
->group
) releaseRunContext();
2561 XRETURN(lstReturnReturned
); /* done */
2563 /* just kill the current run group */
2564 while (curGroup
->group
) releaseRunContext();
2565 free(removeCurrentGroup());
2567 /* the current group is dead, go on with the next */
2571 /* check if we should do unwinding and possibly group switching */
2572 if (context
->data
[lstIVprocOwnerInContext
] != aProcess
) {
2573 /* yes, this is inter-process return; do unwinding */
2574 op
= context
->data
[lstIVprocOwnerInContext
];
2575 dprintf(" ct=%p\n", context
);
2576 dprintf(" op=%p\n", op
);
2577 dprintf(" nl=%p\n", lstNilObj
);
2578 /* first try our own process group */
2579 if (groupHasProcess(curGroup
, op
)) {
2580 /* unwinding in current process group */
2581 while (curGroup
->group
->process
!= op
) releaseRunContext();
2584 /* not in the current group; this means that the current group is effectively dead */
2585 /* remove current group */
2586 if (curGroup
== runGroups
) {
2588 while (curGroup
->group
->prev
) releaseRunContext();
2589 aProcess
= runGroups
->group
->process
; /* initial process */
2590 aProcess
->data
[lstIVresultInProcess
] = retValue
;
2591 aProcess
->data
[lstIVcontextInProcess
] = lstNilObj
;
2592 /* clear the current run group */
2593 while (curGroup
->group
) releaseRunContext();
2594 XRETURN(lstReturnReturned
); /* done */
2596 while (curGroup
->group
) releaseRunContext();
2597 free(removeCurrentGroup());
2598 /* inter-group communications should be done with events, so just shedule to the next process */
2603 case lstBXDuplicate
:
2604 DBG0("DoSpecial: Duplicate");
2605 assert(stackTop
> 0);
2606 retValue
= stack
->data
[stackTop
-1];
2610 DBG0("DoSpecial: PopTop");
2611 assert(stackTop
> 0);
2615 DBG0("DoSpecial: Branch");
2619 case lstBXBranchIfTrue
:
2620 DBG0("DoSpecial: BranchIfTrue");
2623 if (retValue
== lstTrueObj
) curIP
= low
; else curIP
+= VALSIZE
;
2625 case lstBXBranchIfFalse
:
2626 DBG0("DoSpecial: BranchIfFalse");
2629 if (retValue
== lstFalseObj
) curIP
= low
; else curIP
+= VALSIZE
;
2631 case lstBXBranchIfNil
:
2632 DBG0("DoSpecial: BranchIfNil");
2635 if (retValue
== lstNilObj
) curIP
= low
; else curIP
+= VALSIZE
;
2637 case lstBXBranchIfNotNil
:
2638 DBG0("DoSpecial: BranchIfNotNil");
2641 if (retValue
!= lstNilObj
) curIP
= low
; else curIP
+= VALSIZE
;
2643 case lstBXSendToSuper
:
2644 DBG0("DoSpecial: SendToSuper");
2645 /* next byte has literal selector number */
2647 messageSelector
= literals
->data
[low
];
2648 receiverClass
= method
->data
[lstIVclassInMethod
]->data
[lstIVparentClassInClass
];
2652 case lstBXThisContext
:
2653 DBG0("DoSpecial: ThisContext");
2656 case lstBXBreakpoint
:
2657 DBG0("DoSpecial: Breakpoint");
2658 /*fprintf(stderr, "BP\n");*/
2659 /* back up on top of the breaking location */
2661 /* return to our master process */
2662 /*aProcess->data[lstIVresultInProcess] = lstNilObj;*/
2663 retValue
= lstNilObj
;
2664 if (doReturn(lstReturnBreak
)) XRETURN(lstReturnBreak
);
2665 if (tmp
|| retGSwitch
) goto doAllAgain
;
2668 lstFatal("invalid doSpecial", low
);
2673 if (curGroup
== runGroups
) {
2674 retValue
= lstNilObj
;
2675 if (doReturn(lstReturnError
)) XRETURN(lstReturnError
);
2676 fprintf(stderr
, "invalid bytecode: %d\n", high
);
2677 if (tmp
|| retGSwitch
) goto doAllAgain
;
2680 lstFatal("invalid bytecode", high
);
2687 int lstExecute (lstObject
*aProcess
, int ticks
, int locked
) {
2689 return lstExecuteInternal(aProcess
, ticks
, locked
);
2693 int lstResume (void) {
2694 if (!lstSuspended
) return -1; /* very fatal error */
2695 return lstExecuteInternal(NULL
, 0, 0);
2699 int lstCanResume (void) {
2700 return lstSuspended
!= 0;
2704 void lstResetResume (void) {
2707 curGroup
= runGroups
;
2708 while (curGroup
->group
) releaseRunContext();
2713 #define RARG (lstRootStack[otop+0])
2714 #define RMETHOD (lstRootStack[otop+1])
2715 #define RPROCESS (lstRootStack[otop+2])
2716 #define RCONTEXT (lstRootStack[otop+3])
2717 int lstRunMethodWithArg (lstObject
*method
, lstObject
*inClass
, lstObject
*arg
, lstObject
**result
, int locked
) {
2719 int otop
= lstRootTop
, x
;
2720 if (result
) *result
= NULL
;
2721 /* save method and arguments */
2722 if (!method
|| method
->stclass
!= lstMethodClass
) return lstReturnError
;
2723 lstRootStack
[LST_RSTACK_NSP()] = arg
;
2724 lstRootStack
[LST_RSTACK_NSP()] = method
;
2725 /* create Process object */
2726 lstRootStack
[LST_RSTACK_NSP()] = lstAllocInstance(lstProcessSize
, lstProcessClass
); /*lstStaticAlloc(lstProcessSize);*/
2727 /* create Context object (must be dynamic) */
2728 lstRootStack
[LST_RSTACK_NSP()] = lstAllocInstance(lstContextSize
, lstContextClass
);
2729 RPROCESS
->data
[lstIVcontextInProcess
] = RCONTEXT
;
2730 x
= lstIntValue(RMETHOD
->data
[lstIVstackSizeInMethod
]);
2731 o
= lstRootStack
[LST_RSTACK_NSP()] = RCONTEXT
->data
[lstIVstackInContext
] = lstAllocInstance(x
, lstArrayClass
);
2732 /*if (x) memset(lstBytePtr(o), 0, x*LST_BYTES_PER_WORD);*/
2733 /* build arguments array */
2734 o
= lstAllocInstance(arg
? 2 : 1, lstArrayClass
);
2735 /*o->data[0] = RCONTEXT;*/
2736 o
->data
[0] = inClass
? inClass
: lstNilObj
->stclass
;
2737 if (arg
) o
->data
[1] = arg
;
2738 RCONTEXT
->data
[lstIVprocOwnerInContext
] = RPROCESS
;
2739 RCONTEXT
->data
[lstIVargumentsInContext
] = o
;
2740 RCONTEXT
->data
[lstIVtemporariesInContext
] = lstAllocInstance(lstIntValue(RMETHOD
->data
[lstIVtemporarySizeInMethod
]), lstArrayClass
);
2741 RCONTEXT
->data
[lstIVbytePointerInContext
] = lstNewInt(0);
2742 RCONTEXT
->data
[lstIVstackTopInContext
] = lstNewInt(0);
2743 RCONTEXT
->data
[lstIVpreviousContextInContext
] = lstNilObj
;
2744 RCONTEXT
->data
[lstIVmethodInContext
] = RMETHOD
;
2746 int res
= lstExecute(RPROCESS
, 0, locked
>0);
2747 if (res
== lstReturnReturned
&& result
) *result
= RPROCESS
->data
[lstIVresultInProcess
];
2748 /*printf("OTOP: %d; TOP: %d\n", otop, lstRootTop);*/
2750 case lstReturnBadMethod
:
2751 fprintf(stderr
, "can't find method in call\n");
2752 o
= RPROCESS
->data
[lstIVresultInProcess
];
2753 fprintf(stderr
, "Unknown method: %s\n", lstBytePtr(o
));
2754 lstBackTrace(RPROCESS
->data
[lstIVcontextInProcess
]);
2756 case lstReturnAPISuspended
:
2757 if (lstExecUserBreak
!= 666) {
2758 fprintf(stderr
, "\nuser break\n");
2759 o
= RPROCESS
->data
[lstIVresultInProcess
];
2760 lstBackTrace(RPROCESS
->data
[lstIVcontextInProcess
]);
2764 if (lstRootTop
> otop
) lstRootTop
= otop
;
2769 void lstCompleteFinalizers (void) {
2772 if (finGroupCount
< 1) break;
2774 dprintf("%d finalizers left\n", finGroupCount
);
2775 lstExecuteInternal(NULL
, 10000, 0);