1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     http://www.audiosynth.com
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24 #include "PyrKernel.h"
25 #include "PyrObject.h"
26 #include "PyrPrimitive.h"
27 #include "PyrPrimitiveProto.h"
28 #include "PyrSignal.h"
29 #include "PyrSched.h"
30 #include "PyrSignalPrim.h"
31 #include "PyrFilePrim.h"
32 #include "PyrMathPrim.h"
33 #include "PyrListPrim.h"
34 #include "Opcodes.h"
35 #include "SC_InlineUnaryOp.h"
36 #include "SC_InlineBinaryOp.h"
37 #include "PyrMessage.h"
38 #include "PyrParseNode.h"
39 #include "PyrLexer.h"
40 #include "PyrKernelProto.h"
41 #include "PyrInterpreter.h"
42 #include "PyrObjectProto.h"
43 #include "PyrArchiverT.h"
44 #include "PyrDeepCopier.h"
45 #include "PyrDeepFreezer.h"
46 //#include "Wacom.h"
47 #include "InitAlloc.h"
48 #include "SC_AudioDevicePrim.hpp"
49 #include "SC_LanguageConfig.hpp"
50 #include "SC_Filesystem.hpp"
51 #include "SC_Version.hpp"
52 #include <map>
53 
54 #ifdef _WIN32
55 #    include <direct.h>
56 #else
57 #    include <sys/param.h>
58 #endif
59 
60 #ifdef SC_QT
61 #    include "QtCollider.h"
62 #endif
63 
64 #include "SCDocPrim.h"
65 
66 #include <boost/filesystem/path.hpp> // path
67 
68 #ifdef __clang__
69 #    pragma clang diagnostic ignored "-Warray-bounds"
70 #endif
71 
72 namespace bfs = boost::filesystem;
73 
74 int yyparse();
75 
76 extern bool gTraceInterpreter;
77 PyrSymbol* s_recvmsg;
78 
79 void initPatternPrimitives();
80 
81 typedef struct {
82     PrimitiveHandler func;
83     PyrSymbol* name;
84     unsigned short base;
85     unsigned char numArgs;
86     unsigned char varArgs;
87     unsigned char keyArgs;
88 } PrimitiveDef;
89 
90 typedef struct {
91     int size, maxsize;
92     PrimitiveDef* table;
93 } PrimitiveTable;
94 
95 extern PrimitiveTable gPrimitiveTable;
96 
97 
getPrimitiveNumArgs(int index)98 int getPrimitiveNumArgs(int index) { return gPrimitiveTable.table[index].numArgs; }
99 
getPrimitiveName(int index)100 PyrSymbol* getPrimitiveName(int index) { return gPrimitiveTable.table[index].name; }
101 
slotStrLen(PyrSlot * slot)102 int slotStrLen(PyrSlot* slot) {
103     if (IsSym(slot))
104         return slotRawSymbol(slot)->length;
105     if (isKindOfSlot(slot, class_string))
106         return slotRawObject(slot)->size;
107 
108     return -1;
109 }
110 
slotStrVal(PyrSlot * slot,char * str,int maxlen)111 int slotStrVal(PyrSlot* slot, char* str, int maxlen) {
112     if (IsSym(slot)) {
113         strncpy(str, slotRawSymbol(slot)->name, maxlen);
114         return errNone;
115     } else if (isKindOfSlot(slot, class_string)) {
116         int len;
117         len = sc_min(maxlen - 1, slotRawObject(slot)->size);
118         memcpy(str, slotRawString(slot)->s, len);
119         str[len] = 0;
120         return errNone;
121     }
122     return errWrongType;
123 }
124 
125 /**
126  * \brief Convert an sclang string or symbol into an std:string
127  * \param slot the sclang string or symbol
128  * \return a tuple containing an int, an error code, and an std:string.
129  *  In case of an error the string will be empty.
130  */
slotStdStrVal(PyrSlot * slot)131 std::tuple<int, std::string> slotStdStrVal(PyrSlot* slot) {
132     return IsSym(slot)
133         ? std::make_tuple(errNone, std::string(slotRawSymbol(slot)->name, (size_t)slotRawSymbol(slot)->length))
134         : (isKindOfSlot(slot, class_string)
135                ? std::make_tuple(errNone, std::string(slotRawString(slot)->s, slotRawObject(slot)->size))
136                : std::make_tuple(errWrongType, std::string()));
137 }
138 
139 /**
140  * \brief Convert an sclang string into an std:string
141  * \param slot the sclang string
142  * \return a tuple containing an int, an error code, and an std:string.
143  *  In case of an error the string will be empty.
144  */
slotStrStdStrVal(PyrSlot * slot)145 std::tuple<int, std::string> slotStrStdStrVal(PyrSlot* slot) {
146     return isKindOfSlot(slot, class_string)
147         ? std::make_tuple(errNone, std::string(slotRawString(slot)->s, slotRawObject(slot)->size))
148         : std::make_tuple(errWrongType, std::string());
149 }
150 
slotPStrVal(PyrSlot * slot,unsigned char * str)151 int slotPStrVal(PyrSlot* slot, unsigned char* str) {
152     if (IsSym(slot)) {
153         strncpy((char*)str + 1, slotRawSymbol(slot)->name, 255);
154         str[0] = slotRawSymbol(slot)->length;
155         return errNone;
156     } else if (isKindOfSlot(slot, class_string)) {
157         int len;
158         len = sc_min(255, slotRawObject(slot)->size);
159         memcpy(str + 1, slotRawString(slot)->s, len);
160         str[0] = len;
161         return errNone;
162     }
163     return errWrongType;
164 }
165 
instVarAt(struct VMGlobals * g,int numArgsPushed)166 int instVarAt(struct VMGlobals* g, int numArgsPushed) {
167     PyrSlot *a, *b;
168     int index;
169 
170     a = g->sp - 1;
171     b = g->sp;
172 
173     if (NotObj(a))
174         return errWrongType;
175 
176     PyrObject* obj = slotRawObject(a);
177 
178     if (IsInt(b)) {
179         index = slotRawInt(b);
180         if (index < 0 || index >= obj->size)
181             return errIndexOutOfRange;
182         slotCopy(a, &obj->slots[index]);
183     } else if (IsSym(b)) {
184         PyrSlot* instVarNamesSlot = &obj->classptr->instVarNames;
185         if (!isKindOfSlot(instVarNamesSlot, class_symbolarray))
186             return errFailed;
187         PyrSymbolArray* instVarNames = slotRawSymbolArray(instVarNamesSlot);
188         PyrSymbol** names = instVarNames->symbols;
189         PyrSymbol* name = slotRawSymbol(b);
190         for (int i = 0; i < instVarNames->size; ++i) {
191             if (names[i] == name) {
192                 slotCopy(a, &obj->slots[i]);
193                 return errNone;
194             }
195         }
196         return errFailed;
197     } else
198         return errWrongType;
199     return errNone;
200 }
201 
instVarPut(struct VMGlobals * g,int numArgsPushed)202 int instVarPut(struct VMGlobals* g, int numArgsPushed) {
203     PyrSlot *a, *b, *c, *slot;
204     int index;
205     PyrObject* obj;
206 
207     a = g->sp - 2;
208     b = g->sp - 1;
209     c = g->sp;
210 
211     if (NotObj(a))
212         return errWrongType;
213     obj = slotRawObject(a);
214     if (obj->IsImmutable())
215         return errImmutableObject;
216 
217     if (IsInt(b)) {
218         index = slotRawInt(b);
219         if (index < 0 || index >= obj->size)
220             return errIndexOutOfRange;
221         slot = obj->slots + index;
222         slotCopy(slot, c);
223         g->gc->GCWrite(obj, slot);
224     } else if (IsSym(b)) {
225         PyrSlot* instVarNamesSlot = &obj->classptr->instVarNames;
226         if (!IsObj(instVarNamesSlot))
227             return errFailed;
228         PyrSymbolArray* instVarNames = slotRawSymbolArray(instVarNamesSlot);
229         PyrSymbol** names = instVarNames->symbols;
230         PyrSymbol* name = slotRawSymbol(b);
231         for (int i = 0; i < instVarNames->size; ++i) {
232             if (names[i] == name) {
233                 slot = obj->slots + i;
234                 slotCopy(slot, c);
235                 g->gc->GCWrite(obj, slot);
236                 return errNone;
237             }
238         }
239         post("WARNING: %s instVarPut '%s' failed.\n", slotRawSymbol(&obj->classptr->name)->name, name->name);
240         return errNone;
241     } else
242         return errWrongType;
243     return errNone;
244 }
245 
instVarSize(struct VMGlobals * g,int numArgsPushed)246 int instVarSize(struct VMGlobals* g, int numArgsPushed) {
247     PyrSlot* a;
248     PyrObject* obj;
249 
250     a = g->sp;
251     if (NotObj(a)) {
252         SetInt(a, 0);
253         return errNone;
254     }
255     obj = slotRawObject(a);
256     if (obj->obj_format == obj_notindexed) {
257         SetInt(a, obj->size);
258     } else {
259         SetInt(a, 0);
260     }
261     return errNone;
262 }
263 
264 
objectHash(struct VMGlobals * g,int numArgsPushed)265 int objectHash(struct VMGlobals* g, int numArgsPushed) {
266     PyrSlot* a;
267     int hash;
268 
269     a = g->sp;
270 
271     hash = calcHash(a);
272     SetInt(a, hash);
273     return errNone;
274 }
275 
objectClass(struct VMGlobals * g,int numArgsPushed)276 int objectClass(struct VMGlobals* g, int numArgsPushed) {
277     PyrSlot* a;
278     PyrClass* classobj;
279 
280     a = g->sp;
281     classobj = classOfSlot(a);
282     SetObject(a, classobj);
283     return errNone;
284 }
285 
prPrimitiveError(struct VMGlobals * g,int numArgsPushed)286 int prPrimitiveError(struct VMGlobals* g, int numArgsPushed) {
287     PyrSlot* a;
288 
289     a = g->sp;
290     slotCopy(a, &g->thread->primitiveError);
291     return errNone;
292 }
293 
294 int prStackDepth(struct VMGlobals* g, int numArgsPushed);
prStackDepth(struct VMGlobals * g,int numArgsPushed)295 int prStackDepth(struct VMGlobals* g, int numArgsPushed) {
296     PyrSlot* a;
297 
298     a = g->sp;
299     SetInt(a, g->gc->StackDepth());
300     return errNone;
301 }
302 
303 extern void DumpStack(VMGlobals* g, PyrSlot* sp);
304 
prDumpStack(struct VMGlobals * g,int numArgsPushed)305 int prDumpStack(struct VMGlobals* g, int numArgsPushed) {
306     DumpStack(g, g->sp);
307     return errNone;
308 }
309 
310 void DumpDetailedBackTrace(VMGlobals* g);
311 int prDumpDetailedBackTrace(struct VMGlobals* g, int numArgsPushed);
prDumpDetailedBackTrace(struct VMGlobals * g,int numArgsPushed)312 int prDumpDetailedBackTrace(struct VMGlobals* g, int numArgsPushed) {
313     DumpDetailedBackTrace(g);
314     return errNone;
315 }
316 
prPrimitiveErrorString(struct VMGlobals * g,int numArgsPushed)317 int prPrimitiveErrorString(struct VMGlobals* g, int numArgsPushed) {
318     PyrSlot* a;
319     PyrString* string;
320     std::string str;
321     std::exception_ptr lastPrimitiveException;
322     char *lastPrimitiveExceptionClass, *lastPrimitiveExceptionMethod;
323 
324     a = g->sp;
325     switch (slotRawInt(&g->thread->primitiveError)) {
326     case errReturn:
327         str = "Return (not an error).";
328         break;
329     case errNone:
330         str = "No Error";
331         break;
332     case errFailed:
333         str = "Failed.";
334         break;
335     case errBadPrimitive:
336         str = "Bad Primitive.";
337         break;
338     case errWrongType:
339         str = "Wrong type.";
340         break;
341     case errIndexNotAnInteger:
342         str = "Index not an Integer";
343         break;
344     case errIndexOutOfRange:
345         str = "Index out of range.";
346         break;
347     case errImmutableObject:
348         str = "Attempted write to immutable object.";
349         break;
350     case errNotAnIndexableObject:
351         str = "Not an indexable object.";
352         break;
353     case errStackOverflow:
354         str = "Stack overflow.";
355         break;
356     case errOutOfMemory:
357         str = "Out of memory.";
358         break;
359     case errCantCallOS:
360         str = "Operation cannot be called from this Process. Try using AppClock instead of SystemClock.";
361         break;
362     case errException: {
363         lastPrimitiveException = g->lastExceptions[g->thread].first;
364         PyrMethod* meth = g->lastExceptions[g->thread].second;
365         lastPrimitiveExceptionClass = slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name;
366         lastPrimitiveExceptionMethod = slotRawSymbol(&meth->name)->name;
367         if (lastPrimitiveException) {
368             try {
369                 std::rethrow_exception(lastPrimitiveException);
370             } catch (const std::exception& e) {
371                 const char* errorString = e.what();
372                 str = std::string("caught exception \'") + errorString + "\' in primitive in method "
373                     + lastPrimitiveExceptionClass + ":" + lastPrimitiveExceptionMethod;
374                 break;
375             }
376         } else {
377             str = std::string("caught unknown exception in primitive in method ") + lastPrimitiveExceptionClass + ":"
378                 + lastPrimitiveExceptionMethod;
379             break;
380         }
381         break;
382     }
383     default:
384         str = "Failed.";
385     }
386     string = newPyrString(g->gc, str.c_str(), 0, true);
387     SetObject(a, string);
388     return errNone;
389 }
390 
391 
prPostString(struct VMGlobals * g,int numArgsPushed)392 int prPostString(struct VMGlobals* g, int numArgsPushed) {
393     PyrSlot* a;
394 
395     a = g->sp;
396     // if (NotObj(a)) return errWrongType;
397     // assume it is a string!
398     postText(slotRawString(a)->s, slotRawString(a)->size);
399     return errNone;
400 }
401 
prPostLine(struct VMGlobals * g,int numArgsPushed)402 int prPostLine(struct VMGlobals* g, int numArgsPushed) {
403     PyrSlot* a;
404 
405     a = g->sp;
406     // if (NotObj(a)) return errWrongType;
407     // assume it is a string!
408     postText(slotRawString(a)->s, slotRawString(a)->size);
409     postChar('\n');
410     return errNone;
411 }
412 
prDebugger(struct VMGlobals * g,int numArgsPushed)413 int prDebugger(struct VMGlobals* g, int numArgsPushed) {
414     PyrSlot* a;
415 
416     a = g->sp;
417     // Debugger();
418     return errNone;
419 }
420 
421 
prObjectString(struct VMGlobals * g,int numArgsPushed)422 int prObjectString(struct VMGlobals* g, int numArgsPushed) {
423     PyrSlot* a;
424     PyrString* string;
425     char str[256];
426 
427     a = g->sp;
428     if (IsSym(a)) {
429         string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true);
430         SetObject(a, string);
431         return errNone;
432     } else if (postString(a, str)) {
433         string = newPyrString(g->gc, str, 0, true);
434         SetObject(a, string);
435         return errNone;
436     } else {
437         return errFailed;
438     }
439 }
440 
441 int prFloat_AsStringPrec(struct VMGlobals* g, int numArgsPushed);
prFloat_AsStringPrec(struct VMGlobals * g,int numArgsPushed)442 int prFloat_AsStringPrec(struct VMGlobals* g, int numArgsPushed) {
443     PyrSlot* a = g->sp - 1;
444     PyrSlot* b = g->sp;
445 
446     int precision;
447     int err = slotIntVal(b, &precision);
448     if (err)
449         return err;
450 
451     char fmt[8], str[256];
452     // if our precision is bigger than our stringsize, we can generate a very nasty buffer overflow here. So
453     if (precision <= 0)
454         precision = 1;
455     if (precision >= 200)
456         precision = 200; // Nothing is that big anyway. And we know we will be smaller than our 256 char string
457 
458     sprintf(fmt, "%%.%dg", precision);
459     sprintf(str, fmt, slotRawFloat(a));
460 
461     PyrString* string = newPyrString(g->gc, str, 0, true);
462     SetObject(a, string);
463     return errNone;
464 }
465 
466 int prAsCompileString(struct VMGlobals* g, int numArgsPushed);
prAsCompileString(struct VMGlobals * g,int numArgsPushed)467 int prAsCompileString(struct VMGlobals* g, int numArgsPushed) {
468     PyrSlot* a;
469     PyrString* string;
470     int err = errNone;
471 
472     a = g->sp;
473     if (IsSym(a)) {
474         int len = strlen(slotRawSymbol(a)->name) + 1;
475         if (len < 255) {
476             char str[256];
477             sprintf(str, "'%s'", slotRawSymbol(a)->name);
478             string = newPyrString(g->gc, str, 0, true);
479         } else {
480             char* str = (char*)malloc(len + 2);
481             sprintf(str, "'%s'", slotRawSymbol(a)->name);
482             string = newPyrString(g->gc, str, 0, true);
483             free(str);
484         }
485     } else {
486         char str[256];
487         err = asCompileString(a, str);
488         if (err)
489             return err;
490         string = newPyrString(g->gc, str, 0, true);
491     }
492     SetObject(a, string);
493     return err;
494 }
495 
496 
prClassString(struct VMGlobals * g,int numArgsPushed)497 int prClassString(struct VMGlobals* g, int numArgsPushed) {
498     PyrSlot* a;
499     PyrClass* classobj;
500     PyrString* string;
501 
502     a = g->sp;
503     classobj = classOfSlot(a);
504     string = newPyrString(g->gc, slotRawSymbol(&classobj->name)->name, 0, true);
505     SetObject(a, string);
506     return errNone;
507 }
508 
509 
prPrimName(struct VMGlobals * g,int numArgsPushed)510 int prPrimName(struct VMGlobals* g, int numArgsPushed) {
511     PyrSlot* a;
512     PyrThread* thread;
513 
514     a = g->sp;
515     thread = slotRawThread(a);
516     if (slotRawInt(&thread->primitiveIndex) <= gPrimitiveTable.size) {
517         SetSymbol(a, gPrimitiveTable.table[slotRawInt(&thread->primitiveIndex)].name);
518     } else {
519         SetSymbol(a, s_none);
520     }
521     return errNone;
522 }
523 
objectIsKindOf(struct VMGlobals * g,int numArgsPushed)524 int objectIsKindOf(struct VMGlobals* g, int numArgsPushed) {
525     PyrSlot *a, *b;
526     PyrClass *classobj, *testclass;
527     int objClassIndex, testClassIndex, maxSubclassIndex;
528 
529     a = g->sp - 1;
530     b = g->sp;
531 
532     if (NotObj(b))
533         return errWrongType;
534     testclass = (PyrClass*)slotRawObject(b);
535     classobj = classOfSlot(a);
536 #if 0
537 	while (classobj) {
538 		if (classobj == testclass) {
539 			SetTrue(a);
540 			return errNone;
541 		}
542 		classobj = slotRawSymbol(&classobj->superclass)->u.classobj;
543 	}
544 	SetFalse(a);
545 #else
546     // constant time lookup method:
547 
548     objClassIndex = slotRawInt(&classobj->classIndex);
549     testClassIndex = slotRawInt(&testclass->classIndex);
550     maxSubclassIndex = slotRawInt(&testclass->maxSubclassIndex);
551 
552     /*post("%s %s\n", slotRawSymbol(&classobj->name)->name, testclass->name.us->name);
553     post("objClassIndex %d\n", objClassIndex);
554     post("testClassIndex %d\n", testClassIndex);
555     post("maxSubclassIndex %d\n", maxSubclassIndex);*/
556 
557     if (objClassIndex >= testClassIndex && objClassIndex <= maxSubclassIndex) {
558         SetTrue(a);
559         return errNone;
560     } else {
561         SetFalse(a);
562         return errNone;
563     }
564 
565 #endif
566     return errNone;
567 }
568 
569 
objectIsMemberOf(struct VMGlobals * g,int numArgsPushed)570 int objectIsMemberOf(struct VMGlobals* g, int numArgsPushed) {
571     PyrSlot *a, *b;
572     PyrClass *classobj, *testclass;
573 
574     a = g->sp - 1;
575     b = g->sp;
576 
577     if (NotObj(b))
578         return errWrongType;
579     testclass = (PyrClass*)slotRawObject(b);
580     classobj = classOfSlot(a);
581     if (classobj == testclass) {
582         SetTrue(a);
583     } else {
584         SetFalse(a);
585     }
586     return errNone;
587 }
588 
objectIdentical(struct VMGlobals * g,int numArgsPushed)589 int objectIdentical(struct VMGlobals* g, int numArgsPushed) {
590     PyrSlot *a, *b;
591 
592     a = g->sp - 1;
593     b = g->sp;
594 
595     if (SlotEq(a, b))
596         SetTrue(a);
597     else
598         SetFalse(a);
599     return errNone;
600 }
601 
objectNotIdentical(struct VMGlobals * g,int numArgsPushed)602 int objectNotIdentical(struct VMGlobals* g, int numArgsPushed) {
603     PyrSlot *a, *b;
604 
605     a = g->sp - 1;
606     b = g->sp;
607 
608     if (!SlotEq(a, b))
609         SetTrue(a);
610     else
611         SetFalse(a);
612     return errNone;
613 }
614 
615 
basicNewClear(struct VMGlobals * g,int numArgsPushed)616 int basicNewClear(struct VMGlobals* g, int numArgsPushed) {
617     PyrSlot *a, *b;
618     int size;
619     PyrClass* classobj;
620     PyrObject* newobj;
621 
622     a = g->sp - 1;
623     b = g->sp;
624 
625     if (NotObj(a))
626         return errWrongType;
627     classobj = (PyrClass*)slotRawObject(a);
628     if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
629         // create an indexable object
630         if (NotInt(b)) {
631             if (IsFloat(b)) {
632                 size = (int)slotRawFloat(b);
633             } else if (NotNil(b))
634                 return errIndexNotAnInteger;
635             else
636                 size = 8;
637         } else {
638             size = slotRawInt(b);
639         }
640         if (size < 0)
641             size = 0;
642     } else {
643         size = 0;
644     }
645     newobj = instantiateObject(g->gc, classobj, size, true, true);
646     SetObject(a, newobj);
647     return errNone;
648 }
649 
650 int basicNewCopyArgsToInstanceVars(struct VMGlobals* g, int numArgsPushed);
basicNewCopyArgsToInstanceVars(struct VMGlobals * g,int numArgsPushed)651 int basicNewCopyArgsToInstanceVars(struct VMGlobals* g, int numArgsPushed) {
652     PyrSlot *a, *b;
653     PyrClass* classobj;
654     PyrObject* newobj;
655 
656     a = g->sp - numArgsPushed + 1;
657     b = a + 1;
658 
659     if (NotObj(a))
660         return errWrongType;
661     classobj = (PyrClass*)slotRawObject(a);
662     if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
663         error("CopyArgs : object has no instance variables.\n");
664         return errFailed;
665     }
666     newobj = instantiateObject(g->gc, classobj, 0, true, true);
667     SetObject(a, newobj);
668 
669     int length = sc_min(numArgsPushed - 1, newobj->size);
670     for (int i = 0; i < length; ++i) {
671         slotCopy(&newobj->slots[i], &b[i]);
672     }
673 
674     return errNone;
675 }
676 
677 
basicNew(struct VMGlobals * g,int numArgsPushed)678 int basicNew(struct VMGlobals* g, int numArgsPushed) {
679     PyrSlot *a, *b;
680     int size;
681     PyrClass* classobj;
682     PyrObject* newobj;
683 
684     a = g->sp - 1;
685     b = g->sp;
686 
687     if (NotObj(a))
688         return errWrongType;
689     classobj = (PyrClass*)slotRawObject(a);
690     if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
691         // create an indexable object
692         if (NotInt(b)) {
693             if (IsFloat(b)) {
694                 size = (int)slotRawFloat(b);
695             } else if (NotNil(b))
696                 return errIndexNotAnInteger;
697             else
698                 size = 8;
699         } else {
700             size = slotRawInt(b);
701         }
702         if (size < 0)
703             size = 0;
704     } else {
705         size = 0;
706     }
707     newobj = instantiateObject(g->gc, classobj, size, false, true);
708     SetObject(a, newobj);
709     return errNone;
710 }
711 
712 
713 bool isClosed(PyrBlock* fundef);
isClosed(PyrBlock * fundef)714 bool isClosed(PyrBlock* fundef) { return IsNil(&fundef->contextDef) && fundef->classptr == class_fundef; }
715 
716 bool isWithinClosed(PyrBlock* fundef);
isWithinClosed(PyrBlock * fundef)717 bool isWithinClosed(PyrBlock* fundef) {
718     while (fundef) {
719         if (isClosed(fundef))
720             return true;
721         fundef = slotRawBlock(&fundef->contextDef);
722     }
723     return false;
724 }
725 
726 int prFunctionDefAsFunction(struct VMGlobals* g, int numArgsPushed);
prFunctionDefAsFunction(struct VMGlobals * g,int numArgsPushed)727 int prFunctionDefAsFunction(struct VMGlobals* g, int numArgsPushed) {
728     PyrSlot* a = g->sp;
729 
730     if (!isClosed(slotRawBlock(a))) {
731         dumpObjectSlot(a);
732         error("Only closed FunctionDef may be converted to a Function using asFunction.\n");
733         return errFailed;
734     }
735 
736     PyrClosure* closure = (PyrClosure*)g->gc->New(2 * sizeof(PyrSlot), 0, obj_notindexed, true);
737 
738     closure->classptr = gSpecialClasses[op_class_func]->u.classobj;
739     closure->size = 2;
740     slotCopy(&closure->block, a);
741     slotCopy(&closure->context, &slotRawInterpreter(&g->process->interpreter)->context);
742     SetObject(a, closure);
743     return errNone;
744 }
745 
746 int prFunctionDefDumpContexts(struct VMGlobals* g, int numArgsPushed);
prFunctionDefDumpContexts(struct VMGlobals * g,int numArgsPushed)747 int prFunctionDefDumpContexts(struct VMGlobals* g, int numArgsPushed) {
748     PyrSlot* a = g->sp;
749 
750     int i = 0;
751     while (slotRawBlock(a)) {
752         post("%2d context %s %p\n", i++, slotRawSymbol(&slotRawObject(a)->classptr->name)->name,
753              slotRawInt(&slotRawBlock(a)->contextDef));
754         a = &slotRawBlock(a)->contextDef;
755     }
756     return errNone;
757 }
758 
759 
760 int prFunctionDefIsClosed(struct VMGlobals* g, int numArgsPushed);
prFunctionDefIsClosed(struct VMGlobals * g,int numArgsPushed)761 int prFunctionDefIsClosed(struct VMGlobals* g, int numArgsPushed) {
762     PyrSlot* a = g->sp;
763     PyrBlock* block = slotRawBlock(a);
764 
765     SetBool(a, isClosed(block));
766     return errNone;
767 }
768 
769 int prFunctionDefIsWithinClosed(struct VMGlobals* g, int numArgsPushed);
prFunctionDefIsWithinClosed(struct VMGlobals * g,int numArgsPushed)770 int prFunctionDefIsWithinClosed(struct VMGlobals* g, int numArgsPushed) {
771     PyrSlot* a = g->sp;
772     PyrBlock* block = slotRawBlock(a);
773 
774     SetBool(a, isWithinClosed(block));
775     return errNone;
776 }
777 
778 
reallocStack(struct VMGlobals * g,int stackNeeded,int stackDepth)779 void reallocStack(struct VMGlobals* g, int stackNeeded, int stackDepth) {
780     // PyrThread *thread = g->thread;
781     PyrGC* gc = g->gc;
782     int newStackSize = NEXTPOWEROFTWO(stackNeeded);
783 
784     PyrObject* array = newPyrArray(gc, newStackSize, 0, false);
785     memcpy(array->slots, gc->Stack()->slots, stackDepth * sizeof(PyrSlot));
786     gc->SetStack(array);
787     gc->ToBlack(gc->Stack());
788     g->sp = array->slots + stackDepth - 1;
789 }
790 
791 
blockValueArray(struct VMGlobals * g,int numArgsPushed)792 int blockValueArray(struct VMGlobals* g, int numArgsPushed) {
793     PyrSlot* b;
794     PyrObject* array;
795     PyrList* list;
796     PyrSlot *pslot, *qslot;
797     int m, size;
798 
799     // a = g->sp - numArgsPushed + 1;
800     b = g->sp;
801 
802     if (IsObj(b)) {
803         if (slotRawObject(b)->classptr == class_array) {
804             array = (PyrObject*)slotRawObject(b);
805         above:
806             size = array->size;
807 
808             PyrObject* stack = g->gc->Stack();
809             int stackDepth = g->sp - stack->slots + 1;
810             int stackSize = ARRAYMAXINDEXSIZE(stack);
811             int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
812             if (stackNeeded > stackSize) {
813                 reallocStack(g, stackNeeded, stackDepth);
814                 b = g->sp;
815             }
816 
817             pslot = array->slots - 1;
818             qslot = b - 1;
819             // pend = (double*)(pslot + size);
820             // while (pslot<pend) slotCopy(++qslot, ++pslot);
821             for (m = 0; m < size; ++m)
822                 slotCopy(++qslot, ++pslot);
823 
824             g->sp += size - 1;
825             return blockValue(g, size + numArgsPushed - 1);
826 
827         } else if (slotRawObject(b)->classptr == class_list) {
828             list = slotRawList(b);
829             if (NotObj(&list->array))
830                 return errWrongType;
831             array = slotRawObject(&list->array);
832             if (array->classptr != class_array)
833                 return errWrongType;
834             goto above;
835         } else { // last arg is not a list or array, so pass as normal
836             return blockValue(g, numArgsPushed);
837         }
838     } else {
839         return blockValue(g, numArgsPushed);
840     }
841 }
842 
843 int blockValueEnvir(struct VMGlobals* g, int numArgsPushed);
844 
845 int blockValueArrayEnvir(struct VMGlobals* g, int numArgsPushed);
blockValueArrayEnvir(struct VMGlobals * g,int numArgsPushed)846 int blockValueArrayEnvir(struct VMGlobals* g, int numArgsPushed) {
847     PyrSlot* b;
848     PyrObject* array;
849     PyrList* list;
850     PyrSlot *pslot, *qslot;
851     int m, size;
852 
853     // a = g->sp - numArgsPushed + 1;
854     b = g->sp;
855 
856     if (IsObj(b)) {
857         if (slotRawObject(b)->classptr == class_array) {
858             array = (PyrObject*)slotRawObject(b);
859         above:
860             size = array->size;
861 
862             PyrObject* stack = g->gc->Stack();
863             int stackDepth = g->sp - stack->slots + 1;
864             int stackSize = ARRAYMAXINDEXSIZE(stack);
865             int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
866             if (stackNeeded > stackSize) {
867                 reallocStack(g, stackNeeded, stackDepth);
868                 b = g->sp;
869             }
870 
871             pslot = array->slots - 1;
872             qslot = b - 1;
873             // pend = (double*)(pslot + size);
874             // while (pslot<pend) slotCopy(++qslot, ++pslot);
875             for (m = 0; m < size; ++m)
876                 slotCopy(++qslot, ++pslot);
877 
878             g->sp += size - 1;
879             return blockValueEnvir(g, size + numArgsPushed - 1);
880 
881         } else if (slotRawObject(b)->classptr == class_list) {
882             list = slotRawList(b);
883             if (NotObj(&list->array))
884                 return errWrongType;
885             array = slotRawObject(&list->array);
886             if (array->classptr != class_array)
887                 return errWrongType;
888             goto above;
889         } else { // last arg is not a list or array, so pass as normal
890             return blockValueEnvir(g, numArgsPushed);
891         }
892     } else {
893         return blockValueEnvir(g, numArgsPushed);
894     }
895 }
896 
blockValue(struct VMGlobals * g,int numArgsPushed)897 HOT int blockValue(struct VMGlobals* g, int numArgsPushed) {
898     PyrSlot* args;
899     PyrSlot* vars;
900     PyrFrame* frame;
901     PyrSlot *pslot, *qslot;
902     PyrSlot* rslot;
903     PyrObject* proto;
904     int i, m, mmax, numtemps;
905     PyrBlock* block;
906     PyrFrame* context;
907     PyrFrame* caller;
908     PyrFrame* homeContext;
909     PyrClosure* closure;
910     PyrMethodRaw* methraw;
911 
912 #if TAILCALLOPTIMIZE
913     int tailCall = g->tailCall;
914     if (tailCall) {
915         if (tailCall == 1) {
916             returnFromMethod(g);
917         } else {
918             returnFromBlock(g);
919         }
920     }
921 #endif
922 
923     g->execMethod = 30;
924 
925     args = g->sp - numArgsPushed + 1;
926 
927     numArgsPushed--;
928     g->numpop = 0;
929 
930     closure = (PyrClosure*)slotRawObject(args);
931     block = slotRawBlock(&closure->block);
932     context = slotRawFrame(&closure->context);
933 
934     proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : nullptr;
935     methraw = METHRAW(block);
936     numtemps = methraw->numtemps;
937     caller = g->frame;
938 
939     frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
940     vars = frame->vars - 1;
941     frame->classptr = class_frame;
942     frame->size = FRAMESIZE + numtemps;
943     SetObject(&frame->method, block);
944     slotCopy(&frame->homeContext, &context->homeContext);
945     slotCopy(&frame->context, &closure->context);
946 
947     if (caller) {
948         SetPtr(&caller->ip, g->ip);
949         SetObject(&frame->caller, g->frame);
950     } else {
951         SetInt(&frame->caller, 0);
952     }
953     SetPtr(&frame->ip, nullptr);
954 
955 
956     g->sp = args - 1;
957     g->ip = slotRawInt8Array(&block->code)->b - 1;
958     g->frame = frame;
959     g->block = block;
960 
961     if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
962         /* push all args to frame */
963         qslot = args;
964         pslot = vars;
965 
966         for (m = 0; m < numArgsPushed; ++m)
967             slotCopy(++pslot, ++qslot);
968 
969         /* push default arg values */
970         pslot = vars + numArgsPushed;
971         qslot = proto->slots + numArgsPushed - 1;
972         for (m = 0; m < numtemps - numArgsPushed; ++m)
973             slotCopy(++pslot, ++qslot);
974     } else if (methraw->varargs) {
975         PyrObject* list;
976         PyrSlot* lslot;
977 
978         /* push all normal args to frame */
979         qslot = args;
980         pslot = vars;
981         for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
982             slotCopy(++pslot, ++qslot);
983 
984         /* push list */
985         i = numArgsPushed - methraw->numargs;
986         list = newPyrArray(g->gc, i, 0, false);
987         list->size = i;
988 
989         rslot = pslot + 1;
990         SetObject(rslot, list);
991         // SetObject(vars + methraw->numargs + 1, list);
992 
993         /* put extra args into list */
994         lslot = list->slots - 1;
995         // fixed and raw sizes are zero
996         for (m = 0; m < i; ++m)
997             slotCopy(++lslot, ++qslot);
998 
999         if (methraw->numvars) {
1000             /* push default keyword and var values */
1001             pslot = vars + methraw->numargs + 1;
1002             qslot = proto->slots + methraw->numargs;
1003             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1004                 slotCopy(++pslot, ++qslot);
1005         }
1006     } else {
1007         if (methraw->numargs) {
1008             /* push all args to frame */
1009             qslot = args;
1010             pslot = vars;
1011             for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1012                 slotCopy(++pslot, ++qslot);
1013         }
1014         if (methraw->numvars) {
1015             /* push default keyword and var values */
1016             pslot = vars + methraw->numargs;
1017             qslot = proto->slots + methraw->numargs - 1;
1018             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1019                 slotCopy(++pslot, ++qslot);
1020         }
1021     }
1022 
1023     homeContext = slotRawFrame(&frame->homeContext);
1024     if (homeContext) {
1025         PyrMethodRaw* methraw;
1026         g->method = slotRawMethod(&homeContext->method);
1027         methraw = METHRAW(g->method);
1028         slotCopy(&g->receiver, &homeContext->vars[0]);
1029     } else {
1030         slotCopy(&g->receiver, &g->process->interpreter);
1031     }
1032 
1033     return errNone;
1034 }
1035 
1036 int blockValueWithKeys(VMGlobals* g, int allArgsPushed, int numKeyArgsPushed);
blockValueWithKeys(VMGlobals * g,int allArgsPushed,int numKeyArgsPushed)1037 int blockValueWithKeys(VMGlobals* g, int allArgsPushed, int numKeyArgsPushed) {
1038     PyrSlot* args;
1039     PyrSlot* vars;
1040     PyrFrame* frame;
1041     PyrSlot *pslot, *qslot;
1042     PyrSlot* rslot;
1043     PyrObject* proto;
1044     int i, j, m, mmax, numtemps, numArgsPushed;
1045     PyrBlock* block;
1046     PyrFrame* context;
1047     PyrFrame* caller;
1048     PyrFrame* homeContext;
1049     PyrClosure* closure;
1050     PyrMethodRaw* methraw;
1051 
1052 #if TAILCALLOPTIMIZE
1053     int tailCall = g->tailCall;
1054     if (tailCall) {
1055         if (tailCall == 1) {
1056             returnFromMethod(g);
1057         } else {
1058             returnFromBlock(g);
1059         }
1060     }
1061 #endif
1062 
1063     g->execMethod = 40;
1064 
1065     args = g->sp - allArgsPushed + 1;
1066 
1067     allArgsPushed--;
1068     g->numpop = 0;
1069 
1070     closure = (PyrClosure*)slotRawObject(args);
1071     block = slotRawBlock(&closure->block);
1072     context = slotRawFrame(&closure->context);
1073 
1074     proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : nullptr;
1075 
1076     methraw = METHRAW(block);
1077     numtemps = methraw->numtemps;
1078     caller = g->frame;
1079     numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1);
1080 
1081     frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1082     vars = frame->vars - 1;
1083     frame->classptr = class_frame;
1084     frame->size = FRAMESIZE + numtemps;
1085     SetObject(&frame->method, block);
1086     slotCopy(&frame->homeContext, &context->homeContext);
1087     slotCopy(&frame->context, &closure->context);
1088 
1089     if (caller) {
1090         SetPtr(&caller->ip, g->ip);
1091         SetObject(&frame->caller, g->frame);
1092     } else {
1093         SetInt(&frame->caller, 0);
1094     }
1095     SetPtr(&frame->ip, nullptr);
1096 
1097     g->sp = args - 1;
1098     g->ip = slotRawInt8Array(&block->code)->b - 1;
1099     g->frame = frame;
1100     g->block = block;
1101 
1102     if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1103         /* push all args to frame */
1104         qslot = args;
1105         pslot = vars;
1106 
1107         for (m = 0; m < numArgsPushed; ++m)
1108             slotCopy(++pslot, ++qslot);
1109 
1110         /* push default arg values */
1111         pslot = vars + numArgsPushed;
1112         qslot = proto->slots + numArgsPushed - 1;
1113         for (m = 0; m < numtemps - numArgsPushed; ++m)
1114             slotCopy(++pslot, ++qslot);
1115     } else if (methraw->varargs) {
1116         PyrObject* list;
1117         PyrSlot* lslot;
1118 
1119         /* push all normal args to frame */
1120         qslot = args;
1121         pslot = vars;
1122         for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1123             slotCopy(++pslot, ++qslot);
1124 
1125         /* push list */
1126         i = numArgsPushed - methraw->numargs;
1127         list = newPyrArray(g->gc, i, 0, false);
1128         list->size = i;
1129 
1130         rslot = pslot + 1;
1131         SetObject(rslot, list);
1132         // SetObject(vars + methraw->numargs + 1, list);
1133 
1134         /* put extra args into list */
1135         lslot = list->slots - 1;
1136         // fixed and raw sizes are zero
1137         // lend = lslot + i;
1138         // while (lslot < lend) slotCopy(++lslot, ++qslot);
1139         for (m = 0; m < i; ++m)
1140             slotCopy(++lslot, ++qslot);
1141 
1142         if (methraw->numvars) {
1143             /* push default keyword and var values */
1144             pslot = vars + methraw->numargs + 1;
1145             qslot = proto->slots + methraw->numargs;
1146             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1147                 slotCopy(++pslot, ++qslot);
1148         }
1149     } else {
1150         if (methraw->numargs) {
1151             /* push all args to frame */
1152             qslot = args;
1153             pslot = vars;
1154             // pend = pslot + methraw->numargs;
1155             // while (pslot < pend) slotCopy(++pslot, ++qslot);
1156             for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1157                 slotCopy(++pslot, ++qslot);
1158         }
1159         if (methraw->numvars) {
1160             /* push default keyword and var values */
1161             pslot = vars + methraw->numargs;
1162             qslot = proto->slots + methraw->numargs - 1;
1163             // pend = pslot + methraw->numvars;
1164             // while (pslot<pend) slotCopy(++pslot, ++qslot);
1165             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1166                 slotCopy(++pslot, ++qslot);
1167         }
1168     }
1169     // do keyword lookup:
1170     if (numKeyArgsPushed && methraw->posargs) {
1171         PyrSlot* key;
1172         PyrSymbol **name0, **name;
1173         name0 = slotRawSymbolArray(&block->argNames)->symbols;
1174         key = args + numArgsPushed + 1;
1175         for (i = 0; i < numKeyArgsPushed; ++i, key += 2) {
1176             name = name0;
1177             for (j = 0; j < methraw->posargs; ++j, ++name) {
1178                 if (*name == slotRawSymbol(key)) {
1179                     slotCopy(&vars[j + 1], &key[1]);
1180                     goto found1;
1181                 }
1182             }
1183             if (gKeywordError) {
1184                 post("WARNING: keyword arg '%s' not found in call to function.\n", slotRawSymbol(key)->name);
1185             }
1186         found1:;
1187         }
1188     }
1189 
1190     homeContext = slotRawFrame(&frame->homeContext);
1191     if (homeContext) {
1192         PyrMethodRaw* methraw;
1193         g->method = slotRawMethod(&homeContext->method);
1194         methraw = METHRAW(g->method);
1195         slotCopy(&g->receiver, &homeContext->vars[0]);
1196     } else {
1197         slotCopy(&g->receiver, &g->process->interpreter);
1198     }
1199     return errNone;
1200 }
1201 
1202 bool identDict_lookupNonNil(PyrObject* dict, PyrSlot* key, int hash, PyrSlot* result);
1203 
blockValueEnvir(struct VMGlobals * g,int numArgsPushed)1204 int blockValueEnvir(struct VMGlobals* g, int numArgsPushed) {
1205     PyrSlot* args;
1206     PyrSlot* vars;
1207     PyrFrame* frame;
1208     PyrSlot *pslot, *qslot;
1209     PyrSlot* rslot;
1210     PyrObject* proto;
1211     int i, m, mmax, numtemps;
1212     PyrBlock* block;
1213     PyrFrame* context;
1214     PyrFrame* caller;
1215     PyrFrame* homeContext;
1216     PyrClosure* closure;
1217     PyrMethodRaw* methraw;
1218     PyrSlot* curEnvirSlot;
1219 
1220 #if TAILCALLOPTIMIZE
1221     int tailCall = g->tailCall;
1222     if (tailCall) {
1223         if (tailCall == 1) {
1224             returnFromMethod(g);
1225         } else {
1226             returnFromBlock(g);
1227         }
1228     }
1229 #endif
1230 
1231     g->execMethod = 50;
1232 
1233     args = g->sp - numArgsPushed + 1;
1234 
1235     numArgsPushed--;
1236     g->numpop = 0;
1237 
1238     closure = (PyrClosure*)slotRawObject(args);
1239     block = slotRawBlock(&closure->block);
1240     context = slotRawFrame(&closure->context);
1241 
1242     proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : nullptr;
1243 
1244     methraw = METHRAW(block);
1245     numtemps = methraw->numtemps;
1246     caller = g->frame;
1247 
1248     frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1249     vars = frame->vars - 1;
1250     frame->classptr = class_frame;
1251     frame->size = FRAMESIZE + numtemps;
1252     SetObject(&frame->method, block);
1253     slotCopy(&frame->homeContext, &context->homeContext);
1254     slotCopy(&frame->context, &closure->context);
1255 
1256     if (caller) {
1257         SetPtr(&caller->ip, g->ip);
1258         SetObject(&frame->caller, g->frame);
1259     } else {
1260         SetInt(&frame->caller, 0);
1261     }
1262     SetPtr(&frame->ip, nullptr);
1263 
1264 
1265     g->sp = args - 1;
1266     g->ip = slotRawInt8Array(&block->code)->b - 1;
1267     g->frame = frame;
1268     g->block = block;
1269 
1270     if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1271         /* push all args to frame */
1272         qslot = args;
1273         pslot = vars;
1274 
1275         for (m = 0; m < numArgsPushed; ++m)
1276             slotCopy(++pslot, ++qslot);
1277 
1278         /* push default arg values */
1279         pslot = vars + numArgsPushed;
1280         qslot = proto->slots + numArgsPushed - 1;
1281         for (m = 0; m < numtemps - numArgsPushed; ++m)
1282             slotCopy(++pslot, ++qslot);
1283 
1284         // replace defaults with environment variables
1285         curEnvirSlot = &g->classvars->slots[1]; // currentEnvironment is the second class var.
1286 
1287         if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) {
1288             PyrSymbol** argNames;
1289             argNames = slotRawSymbolArray(&block->argNames)->symbols;
1290             for (m = numArgsPushed; m < methraw->numargs; ++m) {
1291                 // replace the args with values from the environment if they exist
1292                 PyrSlot keyslot;
1293                 SetSymbol(&keyslot, argNames[m]);
1294                 identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars + m + 1);
1295             }
1296         }
1297     } else if (methraw->varargs) {
1298         PyrObject* list;
1299         PyrSlot* lslot;
1300 
1301         /* push all normal args to frame */
1302         qslot = args;
1303         pslot = vars;
1304         for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1305             slotCopy(++pslot, ++qslot);
1306 
1307         /* push list */
1308         i = numArgsPushed - methraw->numargs;
1309         list = newPyrArray(g->gc, i, 0, false);
1310         list->size = i;
1311 
1312         rslot = pslot + 1;
1313         SetObject(rslot, list);
1314         // SetObject(vars + methraw->numargs + 1, list);
1315 
1316         /* put extra args into list */
1317         lslot = list->slots - 1;
1318         // fixed and raw sizes are zero
1319         for (m = 0; m < i; ++m)
1320             slotCopy(++lslot, ++qslot);
1321 
1322         if (methraw->numvars) {
1323             /* push default keyword and var values */
1324             pslot = vars + methraw->numargs + 1;
1325             qslot = proto->slots + methraw->numargs;
1326             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1327                 slotCopy(++pslot, ++qslot);
1328         }
1329     } else {
1330         if (methraw->numargs) {
1331             /* push all args to frame */
1332             qslot = args;
1333             pslot = vars;
1334             for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1335                 slotCopy(++pslot, ++qslot);
1336         }
1337         if (methraw->numvars) {
1338             /* push default keyword and var values */
1339             pslot = vars + methraw->numargs;
1340             qslot = proto->slots + methraw->numargs - 1;
1341             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1342                 slotCopy(++pslot, ++qslot);
1343         }
1344     }
1345 
1346     homeContext = slotRawFrame(&frame->homeContext);
1347     if (homeContext) {
1348         PyrMethodRaw* methraw;
1349         g->method = slotRawMethod(&homeContext->method);
1350         methraw = METHRAW(g->method);
1351         slotCopy(&g->receiver, &homeContext->vars[0]);
1352     } else {
1353         slotCopy(&g->receiver, &g->process->interpreter);
1354     }
1355     return errNone;
1356 }
1357 
1358 int blockValueEnvirWithKeys(VMGlobals* g, int allArgsPushed, int numKeyArgsPushed);
blockValueEnvirWithKeys(VMGlobals * g,int allArgsPushed,int numKeyArgsPushed)1359 int blockValueEnvirWithKeys(VMGlobals* g, int allArgsPushed, int numKeyArgsPushed) {
1360     PyrSlot* args;
1361     PyrSlot* vars;
1362     PyrFrame* frame;
1363     PyrSlot *pslot, *qslot;
1364     PyrSlot* rslot;
1365     PyrObject* proto;
1366     int i, j, m, mmax, numtemps, numArgsPushed;
1367     PyrBlock* block;
1368     PyrFrame* context;
1369     PyrFrame* caller;
1370     PyrFrame* homeContext;
1371     PyrClosure* closure;
1372     PyrMethodRaw* methraw;
1373     PyrSlot* curEnvirSlot;
1374 
1375 #if TAILCALLOPTIMIZE
1376     int tailCall = g->tailCall;
1377     if (tailCall) {
1378         if (tailCall == 1) {
1379             returnFromMethod(g);
1380         } else {
1381             returnFromBlock(g);
1382         }
1383     }
1384 #endif
1385 
1386     g->execMethod = 60;
1387 
1388     args = g->sp - allArgsPushed + 1;
1389 
1390     allArgsPushed--;
1391     g->numpop = 0;
1392 
1393     closure = (PyrClosure*)slotRawObject(args);
1394     block = slotRawBlock(&closure->block);
1395     context = slotRawFrame(&closure->context);
1396 
1397     proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : nullptr;
1398 
1399     methraw = METHRAW(block);
1400     numtemps = methraw->numtemps;
1401     caller = g->frame;
1402     numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1);
1403 
1404     frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1405     vars = frame->vars - 1;
1406     frame->classptr = class_frame;
1407     frame->size = FRAMESIZE + numtemps;
1408     SetObject(&frame->method, block);
1409     slotCopy(&frame->homeContext, &context->homeContext);
1410     slotCopy(&frame->context, &closure->context);
1411 
1412     if (caller) {
1413         SetPtr(&caller->ip, g->ip);
1414         SetObject(&frame->caller, g->frame);
1415     } else {
1416         SetInt(&frame->caller, 0);
1417     }
1418     SetPtr(&frame->ip, nullptr);
1419 
1420 
1421     g->sp = args - 1;
1422     g->ip = slotRawInt8Array(&block->code)->b - 1;
1423     g->frame = frame;
1424     g->block = block;
1425 
1426     if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1427         /* push all args to frame */
1428         qslot = args;
1429         pslot = vars;
1430 
1431         for (m = 0; m < numArgsPushed; ++m)
1432             slotCopy(++pslot, ++qslot);
1433 
1434         /* push default arg values */
1435         pslot = vars + numArgsPushed;
1436         qslot = proto->slots + numArgsPushed - 1;
1437         for (m = 0; m < numtemps - numArgsPushed; ++m)
1438             slotCopy(++pslot, ++qslot);
1439 
1440         // replace defaults with environment variables
1441         curEnvirSlot = &g->classvars->slots[1]; // currentEnvironment is the second class var.
1442 
1443         if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) {
1444             PyrSymbol** argNames;
1445             argNames = slotRawSymbolArray(&block->argNames)->symbols;
1446             for (m = numArgsPushed; m < methraw->numargs; ++m) {
1447                 // replace the args with values from the environment if they exist
1448                 PyrSlot keyslot;
1449                 SetSymbol(&keyslot, argNames[m]);
1450                 identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars + m + 1);
1451             }
1452         }
1453 
1454 
1455     } else if (methraw->varargs) {
1456         PyrObject* list;
1457         PyrSlot* lslot;
1458 
1459         /* push all normal args to frame */
1460         qslot = args;
1461         pslot = vars;
1462         for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1463             slotCopy(++pslot, ++qslot);
1464 
1465         /* push list */
1466         i = numArgsPushed - methraw->numargs;
1467         list = newPyrArray(g->gc, i, 0, false);
1468         list->size = i;
1469 
1470         rslot = pslot + 1;
1471         SetObject(rslot, list);
1472         // SetObject(vars + methraw->numargs + 1, list);
1473 
1474         /* put extra args into list */
1475         lslot = list->slots - 1;
1476         // fixed and raw sizes are zero
1477         // lend = lslot + i;
1478         // while (lslot < lend) slotCopy(++lslot, ++qslot);
1479         for (m = 0; m < i; ++m)
1480             slotCopy(++lslot, ++qslot);
1481 
1482         if (methraw->numvars) {
1483             /* push default keyword and var values */
1484             pslot = vars + methraw->numargs + 1;
1485             qslot = proto->slots + methraw->numargs;
1486             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1487                 slotCopy(++pslot, ++qslot);
1488         }
1489     } else {
1490         if (methraw->numargs) {
1491             /* push all args to frame */
1492             qslot = args;
1493             pslot = vars;
1494             // pend = pslot + methraw->numargs;
1495             // while (pslot < pend) slotCopy(++pslot, ++qslot);
1496             for (m = 0, mmax = methraw->numargs; m < mmax; ++m)
1497                 slotCopy(++pslot, ++qslot);
1498         }
1499         if (methraw->numvars) {
1500             /* push default keyword and var values */
1501             pslot = vars + methraw->numargs;
1502             qslot = proto->slots + methraw->numargs - 1;
1503             // pend = pslot + methraw->numvars;
1504             // while (pslot<pend) slotCopy(++pslot, ++qslot);
1505             for (m = 0, mmax = methraw->numvars; m < mmax; ++m)
1506                 slotCopy(++pslot, ++qslot);
1507         }
1508     }
1509     // do keyword lookup:
1510     if (numKeyArgsPushed && methraw->posargs) {
1511         PyrSymbol **name0, **name;
1512         PyrSlot* key;
1513         name0 = slotRawSymbolArray(&block->argNames)->symbols;
1514         key = args + numArgsPushed + 1;
1515         for (i = 0; i < numKeyArgsPushed; ++i, key += 2) {
1516             name = name0;
1517             for (j = 0; j < methraw->posargs; ++j, ++name) {
1518                 if (*name == slotRawSymbol(key)) {
1519                     slotCopy(&vars[j + 1], &key[1]);
1520                     goto found1;
1521                 }
1522             }
1523             if (gKeywordError) {
1524                 post("WARNING: keyword arg '%s' not found in call to function.\n", slotRawSymbol(key)->name);
1525             }
1526         found1:;
1527         }
1528     }
1529 
1530     homeContext = slotRawFrame(&frame->homeContext);
1531     if (homeContext) {
1532         PyrMethodRaw* methraw;
1533         g->method = slotRawMethod(&homeContext->method);
1534         methraw = METHRAW(g->method);
1535         slotCopy(&g->receiver, &homeContext->vars[0]);
1536     } else {
1537         slotCopy(&g->receiver, &g->process->interpreter);
1538     }
1539     return errNone;
1540 }
1541 
1542 
objectPerform(struct VMGlobals * g,int numArgsPushed)1543 int objectPerform(struct VMGlobals* g, int numArgsPushed) {
1544     PyrSlot *recvrSlot, *selSlot, *listSlot;
1545     PyrSlot *pslot, *qslot;
1546     PyrSymbol* selector;
1547     int m, mmax;
1548 
1549     recvrSlot = g->sp - numArgsPushed + 1;
1550     selSlot = recvrSlot + 1;
1551 
1552     if (IsSym(selSlot)) {
1553         selector = slotRawSymbol(selSlot);
1554 
1555         // move args down one to fill selector's position
1556         pslot = selSlot - 1;
1557         qslot = selSlot;
1558         for (m = 0; m < numArgsPushed - 2; ++m)
1559             slotCopy(++pslot, ++qslot);
1560         g->sp--;
1561         numArgsPushed--;
1562         // now the stack looks just like it would for a normal message send
1563     } else if (IsObj(selSlot)) {
1564         // if a List was passed, cast it to an Array, else throw an error
1565         listSlot = selSlot;
1566         if (slotRawObject(listSlot)->classptr == class_list) {
1567             listSlot = slotRawObject(listSlot)->slots;
1568         }
1569         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1570             goto badselector;
1571         }
1572 
1573         PyrObject* array = slotRawObject(listSlot);
1574 
1575         if (array->size < 1) {
1576             error("Array must have a selector.\n");
1577             return errFailed;
1578         }
1579 
1580         selSlot = array->slots;
1581 
1582         // check the first slot to see if it's a symbol
1583         if (NotSym(selSlot)) {
1584             error("First element of array must be a Symbol selector.\n");
1585             dumpObjectSlot(selSlot);
1586             return errWrongType;
1587         }
1588 
1589         selector = slotRawSymbol(selSlot);
1590 
1591         if (numArgsPushed > 2) {
1592             qslot = recvrSlot + numArgsPushed;
1593             pslot = recvrSlot + numArgsPushed + array->size - 2;
1594             for (m = 0; m < numArgsPushed - 2; ++m)
1595                 slotCopy(--pslot, --qslot);
1596         }
1597 
1598         pslot = recvrSlot;
1599         qslot = selSlot;
1600         for (m = 0, mmax = array->size - 1; m < mmax; ++m)
1601             slotCopy(++pslot, ++qslot);
1602 
1603         g->sp += array->size - 2;
1604         numArgsPushed += array->size - 2;
1605         // now the stack looks just like it would for a normal message send
1606 
1607     } else {
1608     badselector:
1609         error("perform selector not a Symbol or Array.\n");
1610         dumpObjectSlot(selSlot);
1611         return errWrongType;
1612     }
1613 
1614     sendMessage(g, selector, numArgsPushed);
1615     g->numpop = 0;
1616     return errNone;
1617 }
1618 
1619 int objectPerformWithKeys(VMGlobals* g, int numArgsPushed, int numKeyArgsPushed);
objectPerformWithKeys(VMGlobals * g,int numArgsPushed,int numKeyArgsPushed)1620 int objectPerformWithKeys(VMGlobals* g, int numArgsPushed, int numKeyArgsPushed) {
1621     PyrSlot *recvrSlot, *selSlot, *listSlot;
1622     PyrSlot *pslot, *qslot;
1623     PyrSymbol* selector;
1624     int m, mmax;
1625 
1626     recvrSlot = g->sp - numArgsPushed + 1;
1627     selSlot = recvrSlot + 1;
1628     if (IsSym(selSlot)) {
1629         selector = slotRawSymbol(selSlot);
1630         // move args down one to fill selector's position
1631         pslot = selSlot - 1;
1632         qslot = selSlot;
1633         for (m = 0; m < numArgsPushed - 2; ++m)
1634             slotCopy(++pslot, ++qslot);
1635         g->sp--;
1636         numArgsPushed--;
1637         // now the stack looks just like it would for a normal message send
1638     } else if (IsObj(selSlot)) {
1639         listSlot = selSlot;
1640         if (slotRawObject(listSlot)->classptr == class_list) {
1641             listSlot = slotRawObject(listSlot)->slots;
1642         }
1643         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1644             goto badselector;
1645         }
1646         PyrObject* array = slotRawObject(listSlot);
1647         if (array->size < 1) {
1648             error("Array must have a selector.\n");
1649             return errFailed;
1650         }
1651         selSlot = array->slots;
1652         selector = slotRawSymbol(selSlot);
1653 
1654         if (numArgsPushed > 2) {
1655             qslot = recvrSlot + numArgsPushed;
1656             pslot = recvrSlot + numArgsPushed + array->size - 2;
1657             for (m = 0; m < numArgsPushed - 2; ++m)
1658                 *--pslot = *--qslot;
1659         }
1660 
1661         pslot = recvrSlot;
1662         qslot = selSlot;
1663         for (m = 0, mmax = array->size - 1; m < mmax; ++m)
1664             slotCopy(++pslot, ++qslot);
1665 
1666         g->sp += array->size - 2;
1667         numArgsPushed += array->size - 2;
1668         // now the stack looks just like it would for a normal message send
1669 
1670     } else {
1671     badselector:
1672         error("perform selector not a Symbol or Array.\n");
1673         dumpObjectSlot(selSlot);
1674         return errWrongType;
1675     }
1676 
1677     sendMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
1678     g->numpop = 0;
1679     return errNone;
1680 }
1681 
1682 
objectPerformList(struct VMGlobals * g,int numArgsPushed)1683 int objectPerformList(struct VMGlobals* g, int numArgsPushed) {
1684     PyrSlot *recvrSlot, *selSlot, *listSlot;
1685     PyrSlot *pslot, *qslot;
1686     PyrSymbol* selector;
1687     int m, mmax, numargslots;
1688     PyrObject* array;
1689 
1690 
1691     recvrSlot = g->sp - numArgsPushed + 1;
1692     selSlot = recvrSlot + 1;
1693     listSlot = g->sp;
1694     numargslots = numArgsPushed - 3;
1695     if (NotSym(selSlot)) {
1696         error("Selector not a Symbol :\n");
1697         return errWrongType;
1698     }
1699     selector = slotRawSymbol(selSlot);
1700 
1701     if (NotObj(listSlot)) {
1702         return objectPerform(g, numArgsPushed);
1703     }
1704     if (slotRawObject(listSlot)->classptr == class_array) {
1705     doarray:
1706         array = slotRawObject(listSlot);
1707 
1708         PyrObject* stack = g->gc->Stack();
1709         int stackDepth = g->sp - stack->slots + 1;
1710         int stackSize = ARRAYMAXINDEXSIZE(stack);
1711         int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
1712         if (stackNeeded > stackSize) {
1713             reallocStack(g, stackNeeded, stackDepth);
1714             recvrSlot = g->sp - numArgsPushed + 1;
1715             selSlot = recvrSlot + 1;
1716         }
1717 
1718         pslot = recvrSlot;
1719         if (numargslots > 0) {
1720             qslot = selSlot;
1721             for (m = 0; m < numargslots; ++m)
1722                 slotCopy(++pslot, ++qslot);
1723         } else
1724             numargslots = 0;
1725         qslot = array->slots - 1;
1726         for (m = 0, mmax = array->size; m < mmax; ++m)
1727             slotCopy(++pslot, ++qslot);
1728     } else if (slotRawObject(listSlot)->classptr == class_list) {
1729         listSlot = slotRawObject(listSlot)->slots;
1730         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1731             error("List array not an Array.\n");
1732             dumpObjectSlot(listSlot);
1733             return errWrongType;
1734         }
1735         goto doarray;
1736     } else {
1737         return objectPerform(g, numArgsPushed);
1738     }
1739     g->sp += array->size - 2;
1740     numArgsPushed = numargslots + array->size + 1;
1741     // now the stack looks just like it would for a normal message send
1742 
1743     sendMessage(g, selector, numArgsPushed);
1744     g->numpop = 0;
1745 
1746     return errNone;
1747 }
1748 
1749 
objectSuperPerform(struct VMGlobals * g,int numArgsPushed)1750 int objectSuperPerform(struct VMGlobals* g, int numArgsPushed) {
1751     PyrSlot *recvrSlot, *selSlot, *listSlot;
1752     PyrSlot *pslot, *qslot;
1753     PyrSymbol* selector;
1754     int m, mmax;
1755 
1756     recvrSlot = g->sp - numArgsPushed + 1;
1757 
1758     PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
1759     if (!isKindOfSlot(recvrSlot, classobj)) {
1760         error("superPerform must be called with 'this' as the receiver.\n");
1761         return errFailed;
1762     }
1763 
1764     selSlot = recvrSlot + 1;
1765     if (IsSym(selSlot)) {
1766         selector = slotRawSymbol(selSlot);
1767         // move args down one to fill selector's position
1768         pslot = selSlot - 1;
1769         qslot = selSlot;
1770         for (m = 0; m < numArgsPushed - 2; ++m)
1771             slotCopy(++pslot, ++qslot);
1772         g->sp--;
1773         numArgsPushed--;
1774         // now the stack looks just like it would for a normal message send
1775     } else if (IsObj(selSlot)) {
1776         listSlot = selSlot;
1777         if (slotRawObject(listSlot)->classptr == class_list) {
1778             listSlot = slotRawObject(listSlot)->slots;
1779         }
1780         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1781             goto badselector;
1782         }
1783         PyrObject* array = slotRawObject(listSlot);
1784         if (array->size < 1) {
1785             error("Array must have a selector.\n");
1786             return errFailed;
1787         }
1788         selSlot = array->slots;
1789         selector = slotRawSymbol(selSlot);
1790 
1791         if (numArgsPushed > 2) {
1792             qslot = recvrSlot + numArgsPushed;
1793             pslot = recvrSlot + numArgsPushed + array->size - 2;
1794             for (m = 0; m < numArgsPushed - 2; ++m)
1795                 slotCopy(--pslot, --qslot);
1796         }
1797 
1798         pslot = recvrSlot;
1799         qslot = selSlot;
1800         for (m = 0, mmax = array->size - 1; m < mmax; ++m)
1801             slotCopy(++pslot, ++qslot);
1802 
1803         g->sp += array->size - 2;
1804         numArgsPushed += array->size - 2;
1805         // now the stack looks just like it would for a normal message send
1806 
1807     } else {
1808     badselector:
1809         error("perform selector not a Symbol or Array.\n");
1810         dumpObjectSlot(selSlot);
1811         return errWrongType;
1812     }
1813 
1814     sendSuperMessage(g, selector, numArgsPushed);
1815     g->numpop = 0;
1816     return errNone;
1817 }
1818 
1819 int objectSuperPerformWithKeys(VMGlobals* g, int numArgsPushed, int numKeyArgsPushed);
objectSuperPerformWithKeys(VMGlobals * g,int numArgsPushed,int numKeyArgsPushed)1820 int objectSuperPerformWithKeys(VMGlobals* g, int numArgsPushed, int numKeyArgsPushed) {
1821     PyrSlot *recvrSlot, *selSlot, *listSlot;
1822     PyrSlot *pslot, *qslot;
1823     PyrSymbol* selector;
1824     int m, mmax;
1825 
1826     recvrSlot = g->sp - numArgsPushed + 1;
1827 
1828     PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
1829     if (!isKindOfSlot(recvrSlot, classobj)) {
1830         error("superPerform must be called with 'this' as the receiver.\n");
1831         return errFailed;
1832     }
1833 
1834     selSlot = recvrSlot + 1;
1835     if (IsSym(selSlot)) {
1836         selector = slotRawSymbol(selSlot);
1837         // move args down one to fill selector's position
1838         pslot = selSlot - 1;
1839         qslot = selSlot;
1840         for (m = 0; m < numArgsPushed - 2; ++m)
1841             slotCopy(++pslot, ++qslot);
1842         g->sp--;
1843         numArgsPushed--;
1844         // now the stack looks just like it would for a normal message send
1845     } else if (IsObj(selSlot)) {
1846         listSlot = selSlot;
1847         if (slotRawObject(listSlot)->classptr == class_list) {
1848             listSlot = slotRawObject(listSlot)->slots;
1849         }
1850         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1851             goto badselector;
1852         }
1853         PyrObject* array = slotRawObject(listSlot);
1854         if (array->size < 1) {
1855             error("Array must have a selector.\n");
1856             return errFailed;
1857         }
1858         selSlot = array->slots;
1859         selector = slotRawSymbol(selSlot);
1860 
1861         if (numArgsPushed > 2) {
1862             qslot = recvrSlot + numArgsPushed;
1863             pslot = recvrSlot + numArgsPushed + array->size - 2;
1864             for (m = 0; m < numArgsPushed - 2; ++m)
1865                 *--pslot = *--qslot;
1866         }
1867 
1868         pslot = recvrSlot;
1869         qslot = selSlot;
1870         for (m = 0, mmax = array->size - 1; m < mmax; ++m)
1871             slotCopy(++pslot, ++qslot);
1872 
1873         g->sp += array->size - 2;
1874         numArgsPushed += array->size - 2;
1875         // now the stack looks just like it would for a normal message send
1876 
1877     } else {
1878     badselector:
1879         error("perform selector not a Symbol or Array.\n");
1880         dumpObjectSlot(selSlot);
1881         return errWrongType;
1882     }
1883 
1884     sendSuperMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
1885     g->numpop = 0;
1886     return errNone;
1887 }
1888 
1889 
objectSuperPerformList(struct VMGlobals * g,int numArgsPushed)1890 int objectSuperPerformList(struct VMGlobals* g, int numArgsPushed) {
1891     PyrSlot *recvrSlot, *selSlot, *listSlot;
1892     PyrSlot *pslot, *qslot;
1893     PyrSymbol* selector;
1894     int m, mmax, numargslots;
1895     PyrObject* array;
1896 
1897     recvrSlot = g->sp - numArgsPushed + 1;
1898     selSlot = recvrSlot + 1;
1899     listSlot = g->sp;
1900     numargslots = numArgsPushed - 3;
1901     if (NotSym(selSlot)) {
1902         error("Selector not a Symbol :\n");
1903         return errWrongType;
1904     }
1905     selector = slotRawSymbol(selSlot);
1906     if (NotObj(listSlot)) {
1907         return objectPerform(g, numArgsPushed);
1908     }
1909     if (slotRawObject(listSlot)->classptr == class_array) {
1910     doarray:
1911         pslot = recvrSlot;
1912         if (numargslots > 0) {
1913             qslot = selSlot;
1914             for (m = 0; m < numargslots; ++m)
1915                 slotCopy(++pslot, ++qslot);
1916         } else
1917             numargslots = 0;
1918         array = slotRawObject(listSlot);
1919         qslot = array->slots - 1;
1920         for (m = 0, mmax = array->size; m < mmax; ++m)
1921             slotCopy(++pslot, ++qslot);
1922     } else if (slotRawObject(listSlot)->classptr == class_list) {
1923         listSlot = slotRawObject(listSlot)->slots;
1924         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1925             error("List array not an Array.\n");
1926             dumpObjectSlot(listSlot);
1927             return errWrongType;
1928         }
1929         goto doarray;
1930     } else {
1931         return objectSuperPerform(g, numArgsPushed);
1932     }
1933     g->sp += array->size - 2;
1934     numArgsPushed = numargslots + array->size + 1;
1935     // now the stack looks just like it would for a normal message send
1936 
1937     sendSuperMessage(g, selector, numArgsPushed);
1938     g->numpop = 0;
1939     return errNone;
1940 }
1941 
1942 
objectPerformSelList(struct VMGlobals * g,int numArgsPushed)1943 int objectPerformSelList(struct VMGlobals* g, int numArgsPushed) {
1944     PyrSlot *recvrSlot, *selSlot, *listSlot;
1945     PyrSlot *pslot, *qslot;
1946     PyrSymbol* selector;
1947     int m, mmax;
1948     PyrObject* array;
1949 
1950     recvrSlot = g->sp - 1;
1951     listSlot = g->sp;
1952 
1953     if (NotObj(listSlot)) {
1954         error("Expected Array or List.. Got :\n");
1955         dumpObjectSlot(listSlot);
1956         return errWrongType;
1957     }
1958     if (slotRawObject(listSlot)->classptr == class_array) {
1959     doarray:
1960         array = slotRawObject(listSlot);
1961 
1962         selSlot = array->slots;
1963         if (NotSym(selSlot)) {
1964             error("Selector not a Symbol :\n");
1965             return errWrongType;
1966         }
1967         selector = slotRawSymbol(selSlot);
1968 
1969         pslot = recvrSlot;
1970         qslot = selSlot;
1971         for (m = 0, mmax = array->size - 1; m < mmax; ++m)
1972             slotCopy(++pslot, ++qslot);
1973     } else if (slotRawObject(listSlot)->classptr == class_list) {
1974         listSlot = slotRawObject(listSlot)->slots;
1975         if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1976             error("List array not an Array.\n");
1977             dumpObjectSlot(listSlot);
1978             return errWrongType;
1979         }
1980         goto doarray;
1981     } else {
1982         error("Expected Array or List.. Got :\n");
1983         dumpObjectSlot(listSlot);
1984         return errWrongType;
1985     }
1986     g->sp += array->size - 2;
1987     numArgsPushed = array->size;
1988     // now the stack looks just like it would for a normal message send
1989 
1990     sendMessage(g, selector, numArgsPushed);
1991     g->numpop = 0;
1992     return errNone;
1993 }
1994 
1995 
1996 int arrayPerformMsg(struct VMGlobals* g, int numArgsPushed);
arrayPerformMsg(struct VMGlobals * g,int numArgsPushed)1997 int arrayPerformMsg(struct VMGlobals* g, int numArgsPushed) {
1998     PyrSlot *recvrSlot, *selSlot, *arraySlot;
1999     PyrSlot *pslot, *qslot;
2000     PyrSymbol* selector;
2001     int m, mmax, numargslots;
2002     PyrObject* array;
2003 
2004     arraySlot = g->sp - numArgsPushed + 1;
2005     array = slotRawObject(arraySlot);
2006     if (array->size < 2) {
2007         error("Array must contain a receiver and a selector.\n");
2008         return errFailed;
2009     }
2010     recvrSlot = array->slots;
2011     selSlot = recvrSlot + 1;
2012     numargslots = numArgsPushed - 1;
2013     if (NotSym(selSlot)) {
2014         error("Selector not a Symbol :\n");
2015         return errWrongType;
2016     }
2017 
2018     selector = slotRawSymbol(selSlot);
2019 
2020     slotCopy(arraySlot, recvrSlot);
2021 
2022     if (numargslots > 0) {
2023         qslot = arraySlot + numargslots + 1;
2024         pslot = arraySlot + numargslots + array->size - 1;
2025         for (m = 0; m < numargslots; ++m)
2026             slotCopy(--pslot, --qslot);
2027     } else
2028         numargslots = 0;
2029 
2030     pslot = arraySlot;
2031     qslot = selSlot;
2032     for (m = 0, mmax = array->size - 2; m < mmax; ++m)
2033         slotCopy(++pslot, ++qslot);
2034 
2035     g->sp += array->size - 2;
2036     numArgsPushed = numargslots + array->size - 1;
2037 
2038     // now the stack looks just like it would for a normal message send
2039 
2040     sendMessage(g, selector, numArgsPushed);
2041     g->numpop = 0;
2042     return errNone;
2043 }
2044 
objectDump(struct VMGlobals * g,int numArgsPushed)2045 int objectDump(struct VMGlobals* g, int numArgsPushed) {
2046     PyrSlot* a;
2047 
2048     a = g->sp;
2049     dumpObjectSlot(a);
2050     return errNone;
2051 }
2052 
2053 
2054 int prTotalFree(struct VMGlobals* g, int numArgsPushed);
prTotalFree(struct VMGlobals * g,int numArgsPushed)2055 int prTotalFree(struct VMGlobals* g, int numArgsPushed) {
2056     PyrSlot* a = g->sp;
2057     SetInt(a, g->allocPool->TotalFree());
2058     return errNone;
2059 }
2060 
2061 int prLargestFreeBlock(struct VMGlobals* g, int numArgsPushed);
prLargestFreeBlock(struct VMGlobals * g,int numArgsPushed)2062 int prLargestFreeBlock(struct VMGlobals* g, int numArgsPushed) {
2063     PyrSlot* a = g->sp;
2064     SetInt(a, g->allocPool->LargestFreeChunk());
2065     return errNone;
2066 }
2067 
2068 int dumpGCinfo(struct VMGlobals* g, int numArgsPushed);
dumpGCinfo(struct VMGlobals * g,int numArgsPushed)2069 int dumpGCinfo(struct VMGlobals* g, int numArgsPushed) {
2070     g->gc->DumpInfo();
2071     return errNone;
2072 }
2073 
2074 int dumpGCdumpGrey(struct VMGlobals* g, int numArgsPushed);
dumpGCdumpGrey(struct VMGlobals * g,int numArgsPushed)2075 int dumpGCdumpGrey(struct VMGlobals* g, int numArgsPushed) {
2076     g->gc->DumpGrey();
2077     return errNone;
2078 }
2079 
2080 int dumpGCdumpSet(struct VMGlobals* g, int numArgsPushed);
dumpGCdumpSet(struct VMGlobals * g,int numArgsPushed)2081 int dumpGCdumpSet(struct VMGlobals* g, int numArgsPushed) {
2082     PyrSlot* b = g->sp;
2083     int set;
2084     int err = slotIntVal(b, &set);
2085     if (err)
2086         return err;
2087 
2088     g->gc->DumpSet(set);
2089     return errNone;
2090 }
2091 
2092 int prGCSanity(struct VMGlobals* g, int numArgsPushed);
prGCSanity(struct VMGlobals * g,int numArgsPushed)2093 int prGCSanity(struct VMGlobals* g, int numArgsPushed) {
2094     g->gc->SanityCheck();
2095     return errNone;
2096 }
2097 
2098 #if GCDEBUG
2099 int prTraceAllPathsTo(struct VMGlobals* g, int numArgsPushed);
prTraceAllPathsTo(struct VMGlobals * g,int numArgsPushed)2100 int prTraceAllPathsTo(struct VMGlobals* g, int numArgsPushed) {
2101     PyrSlot* a = g->sp;
2102     g->gc->TracePathsTo(slotRawObject(a), false);
2103     return errNone;
2104 }
2105 
2106 int prTraceAnyPathsTo(struct VMGlobals* g, int numArgsPushed);
prTraceAnyPathsTo(struct VMGlobals * g,int numArgsPushed)2107 int prTraceAnyPathsTo(struct VMGlobals* g, int numArgsPushed) {
2108     PyrSlot* a = g->sp;
2109     g->gc->TracePathsTo(slotRawObject(a), true);
2110     return errNone;
2111 }
2112 
2113 int prTraceAnyPathToAllInstancesOf(struct VMGlobals* g, int numArgsPushed);
prTraceAnyPathToAllInstancesOf(struct VMGlobals * g,int numArgsPushed)2114 int prTraceAnyPathToAllInstancesOf(struct VMGlobals* g, int numArgsPushed) {
2115     PyrSlot* a = g->sp;
2116     g->gc->TraceAnyPathToAllInstancesOf(slotRawClass(a)->name.us);
2117     return errNone;
2118 }
2119 #endif
2120 
2121 extern PyrClass* gClassList;
2122 
prAllClasses(struct VMGlobals * g,int numArgsPushed)2123 int prAllClasses(struct VMGlobals* g, int numArgsPushed) {
2124     PyrSlot* a;
2125     PyrClass* classobj;
2126     PyrObject* array;
2127     int i;
2128 
2129     a = g->sp;
2130 
2131     array = newPyrArray(g->gc, gNumClasses, 0, true);
2132     classobj = gClassList;
2133     for (i = 0; classobj; ++i) {
2134         SetObject(array->slots + i, classobj);
2135         classobj = slotRawClass(&classobj->nextclass);
2136     }
2137     array->size = gNumClasses;
2138     SetObject(a, array);
2139     return errNone;
2140 }
2141 
prPostClassTree(struct VMGlobals * g,int numArgsPushed)2142 int prPostClassTree(struct VMGlobals* g, int numArgsPushed) {
2143     PyrSlot* a;
2144 
2145     a = g->sp;
2146     postClassTree(slotRawClass(a), 0);
2147     return errNone;
2148 }
2149 
prDumpBackTrace(struct VMGlobals * g,int numArgsPushed)2150 int prDumpBackTrace(struct VMGlobals* g, int numArgsPushed) {
2151     PyrSlot* a;
2152 
2153     a = g->sp;
2154     DumpBackTrace(g);
2155     return errNone;
2156 }
2157 
2158 /* the DebugFrameConstructor uses a work queue in order to avoid recursions, which could lead to stack overflows */
2159 struct DebugFrameConstructor {
makeDebugFrameDebugFrameConstructor2160     void makeDebugFrame(VMGlobals* g, PyrFrame* frame, PyrSlot* outSlot) {
2161         workQueue.push_back(std::make_pair(frame, outSlot));
2162         run_queue(g);
2163     }
2164 
2165 private:
run_queueDebugFrameConstructor2166     void run_queue(VMGlobals* g) {
2167         while (!workQueue.empty()) {
2168             WorkQueueItem work = workQueue.back();
2169             workQueue.pop_back();
2170             fillDebugFrame(g, work.first, work.second);
2171         }
2172     }
2173 
fillDebugFrameDebugFrameConstructor2174     void fillDebugFrame(VMGlobals* g, PyrFrame* frame, PyrSlot* outSlot) {
2175         PyrMethod* meth = slotRawMethod(&frame->method);
2176         PyrMethodRaw* methraw = METHRAW(meth);
2177 
2178         PyrObject* debugFrameObj = instantiateObject(g->gc, getsym("DebugFrame")->u.classobj, 0, false, false);
2179         SetObject(outSlot, debugFrameObj);
2180 
2181         SetObject(debugFrameObj->slots + 0, meth);
2182         SetPtr(debugFrameObj->slots + 5, meth);
2183 
2184         int numargs = methraw->numargs;
2185         int numvars = methraw->numvars;
2186         if (numargs) {
2187             PyrObject* argArray = (PyrObject*)newPyrArray(g->gc, numargs, 0, false);
2188             SetObject(debugFrameObj->slots + 1, argArray);
2189             for (int i = 0; i < numargs; ++i)
2190                 slotCopy(&argArray->slots[i], &frame->vars[i]);
2191 
2192             argArray->size = numargs;
2193         } else
2194             SetNil(debugFrameObj->slots + 1);
2195 
2196         if (numvars) {
2197             PyrObject* varArray = (PyrObject*)newPyrArray(g->gc, numvars, 0, false);
2198             SetObject(debugFrameObj->slots + 2, varArray);
2199             for (int i = 0, j = numargs; i < numvars; ++i, ++j)
2200                 slotCopy(&varArray->slots[i], &frame->vars[j]);
2201 
2202             varArray->size = numvars;
2203         } else
2204             SetNil(debugFrameObj->slots + 2);
2205 
2206         if (slotRawFrame(&frame->caller)) {
2207             WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->caller), debugFrameObj->slots + 3);
2208             workQueue.push_back(newWork);
2209         } else
2210             SetNil(debugFrameObj->slots + 3);
2211 
2212         if (IsObj(&frame->context) && slotRawFrame(&frame->context) == frame)
2213             SetObject(debugFrameObj->slots + 4, debugFrameObj);
2214         else if (NotNil(&frame->context)) {
2215             WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->context), debugFrameObj->slots + 4);
2216             workQueue.push_back(newWork);
2217         } else
2218             SetNil(debugFrameObj->slots + 4);
2219     }
2220 
2221     typedef std::pair<PyrFrame*, PyrSlot*> WorkQueueItem;
2222     typedef std::vector<WorkQueueItem> WorkQueueType;
2223     WorkQueueType workQueue;
2224 };
2225 
MakeDebugFrame(VMGlobals * g,PyrFrame * frame,PyrSlot * outSlot)2226 static void MakeDebugFrame(VMGlobals* g, PyrFrame* frame, PyrSlot* outSlot) {
2227     DebugFrameConstructor constructor;
2228     constructor.makeDebugFrame(g, frame, outSlot);
2229 }
2230 
2231 int prGetBackTrace(VMGlobals* g, int numArgsPushed);
prGetBackTrace(VMGlobals * g,int numArgsPushed)2232 int prGetBackTrace(VMGlobals* g, int numArgsPushed) {
2233     PyrSlot* a;
2234 
2235     a = g->sp;
2236     MakeDebugFrame(g, g->frame, a);
2237 
2238     return errNone;
2239 }
2240 
prObjectShallowCopy(struct VMGlobals * g,int numArgsPushed)2241 int prObjectShallowCopy(struct VMGlobals* g, int numArgsPushed) {
2242     PyrSlot* a;
2243 
2244     a = g->sp;
2245     switch (GetTag(a)) {
2246     case tagObj:
2247         SetRaw(a, copyObject(g->gc, slotRawObject(a), true));
2248         break;
2249         // the default case is to leave the argument unchanged on the stack
2250     }
2251     return errNone;
2252 }
2253 
2254 int prObjectCopyImmutable(struct VMGlobals* g, int numArgsPushed);
prObjectCopyImmutable(struct VMGlobals * g,int numArgsPushed)2255 int prObjectCopyImmutable(struct VMGlobals* g, int numArgsPushed) {
2256     PyrSlot* a;
2257 
2258     a = g->sp;
2259     switch (GetTag(a)) {
2260     case tagObj:
2261         if (slotRawObject(a)->obj_flags & obj_immutable) {
2262             SetRaw(a, copyObject(g->gc, slotRawObject(a), true));
2263         }
2264         break;
2265     }
2266     return errNone;
2267 }
2268 
2269 int prObjectIsMutable(struct VMGlobals* g, int numArgsPushed);
prObjectIsMutable(struct VMGlobals * g,int numArgsPushed)2270 int prObjectIsMutable(struct VMGlobals* g, int numArgsPushed) {
2271     PyrSlot* a;
2272 
2273     a = g->sp;
2274     if (IsObj(a)) {
2275         if (slotRawObject(a)->obj_flags & obj_immutable) {
2276             SetFalse(a);
2277         } else {
2278             SetTrue(a);
2279         }
2280     } else {
2281         SetFalse(a);
2282     }
2283     return errNone;
2284 }
2285 
2286 int prObjectIsPermanent(struct VMGlobals* g, int numArgsPushed);
prObjectIsPermanent(struct VMGlobals * g,int numArgsPushed)2287 int prObjectIsPermanent(struct VMGlobals* g, int numArgsPushed) {
2288     PyrSlot* a;
2289 
2290     a = g->sp;
2291     if (IsObj(a)) {
2292         if (slotRawObject(a)->gc_color == obj_permanent) {
2293             SetTrue(a);
2294         } else {
2295             SetFalse(a);
2296         }
2297     } else {
2298         SetTrue(a);
2299     }
2300     return errNone;
2301 }
2302 
2303 
2304 int prDeepFreeze(struct VMGlobals* g, int numArgsPushed);
prDeepFreeze(struct VMGlobals * g,int numArgsPushed)2305 int prDeepFreeze(struct VMGlobals* g, int numArgsPushed) {
2306     PyrSlot* a;
2307 
2308     a = g->sp;
2309     PyrDeepFreezer freezer(g);
2310     int err = freezer.doDeepFreeze(a);
2311     return err;
2312 }
2313 
2314 
2315 int prDeepCopy(struct VMGlobals* g, int numArgsPushed);
prDeepCopy(struct VMGlobals * g,int numArgsPushed)2316 int prDeepCopy(struct VMGlobals* g, int numArgsPushed) {
2317     PyrSlot* a;
2318 
2319     a = g->sp;
2320     PyrDeepCopier copier(g);
2321     int err = copier.doDeepCopy(a);
2322     return err;
2323 }
2324 
2325 
2326 bool IsSimpleLiteralSlot(PyrSlot* slot);
IsSimpleLiteralSlot(PyrSlot * slot)2327 bool IsSimpleLiteralSlot(PyrSlot* slot) {
2328     switch (GetTag(slot)) {
2329     case tagObj:
2330         return slotRawObject(slot)->IsPermanent();
2331     case tagInt:
2332         return true;
2333     case tagSym:
2334         return true;
2335     case tagChar:
2336         return true;
2337     case tagNil:
2338         return true;
2339     case tagFalse:
2340         return true;
2341     case tagTrue:
2342         return true;
2343     case tagPtr:
2344         return false;
2345     default:
2346         return true;
2347     }
2348 }
2349 
2350 
prObjectCopyRange(struct VMGlobals * g,int numArgsPushed)2351 int prObjectCopyRange(struct VMGlobals* g, int numArgsPushed) {
2352     PyrSlot *a, *b, *c;
2353 
2354     a = g->sp - 2;
2355     b = g->sp - 1;
2356     c = g->sp;
2357 
2358     if (NotObj(a))
2359         return errWrongType;
2360     if (NotInt(b))
2361         return errWrongType;
2362     if (NotInt(c))
2363         return errWrongType;
2364     SetRaw(a, copyObjectRange(g->gc, slotRawObject(a), slotRawInt(b), slotRawInt(c), true));
2365 
2366     return errNone;
2367 }
2368 
2369 
prObjectCopySeries(struct VMGlobals * g,int numArgsPushed)2370 int prObjectCopySeries(struct VMGlobals* g, int numArgsPushed) {
2371     PyrSlot *a, *b, *c, *d;
2372 
2373     a = g->sp - 3;
2374     b = g->sp - 2;
2375     c = g->sp - 1;
2376     d = g->sp;
2377 
2378     PyrObject* inobj = slotRawObject(a);
2379     PyrObject* newobj;
2380 
2381     int size = inobj->size;
2382     int flags = ~(obj_immutable)&inobj->obj_flags;
2383 
2384     int first, second, last;
2385 
2386     if (IsInt(b))
2387         first = slotRawInt(b);
2388     else if (IsNil(b))
2389         first = 0;
2390     else
2391         return errWrongType;
2392 
2393     if (IsInt(d)) {
2394         last = slotRawInt(d);
2395         if (last < 0 && IsNil(b)) {
2396         zerolength:
2397             newobj = g->gc->New(0, flags, inobj->obj_format, true);
2398             newobj->size = 0;
2399             newobj->classptr = inobj->classptr;
2400             SetRaw(a, newobj);
2401             return errNone;
2402         }
2403     } else if (IsNil(d)) {
2404         if (first >= size)
2405             goto zerolength;
2406         last = size - 1;
2407     } else
2408         return errWrongType;
2409 
2410     if (IsInt(c))
2411         second = slotRawInt(c);
2412     else if (IsNil(c))
2413         second = first < last ? first + 1 : first - 1;
2414     else
2415         return errWrongType;
2416 
2417     int step = second - first;
2418 
2419     int elemsize = gFormatElemSize[inobj->obj_format];
2420     int length;
2421 
2422     if (step > 0) {
2423         length = (last - first) / step + 1;
2424     } else if (step < 0) {
2425         length = (first - last) / -step + 1;
2426     } else
2427         return errFailed;
2428 
2429     int numbytes = length * elemsize;
2430 
2431     newobj = g->gc->New(numbytes, flags, inobj->obj_format, true);
2432     newobj->size = 0;
2433     newobj->classptr = inobj->classptr;
2434 
2435     for (int i = first, j = 0; j < length; i += step, ++j) {
2436         PyrSlot slot;
2437         if (i >= 0 && i < inobj->size) {
2438             getIndexedSlot(inobj, &slot, i);
2439             int err = putIndexedSlot(g, newobj, &slot, newobj->size++);
2440             if (err)
2441                 return err;
2442         }
2443     }
2444 
2445     SetRaw(a, newobj);
2446     return errNone;
2447 }
2448 
2449 void switchToThread(struct VMGlobals* g, struct PyrThread* newthread, int oldstate, int* numArgsPushed);
2450 
haltInterpreter(struct VMGlobals * g,int numArgsPushed)2451 int haltInterpreter(struct VMGlobals* g, int numArgsPushed) {
2452     switchToThread(g, slotRawThread(&g->process->mainThread), tDone, &numArgsPushed);
2453     // return all the way out.
2454     // PyrSlot *bottom = g->gc->Stack()->slots;
2455     // slotCopy(bottom,g->sp);
2456     // g->sp = bottom; // ??!! pop everybody
2457     g->method = nullptr;
2458     g->block = nullptr;
2459     g->frame = nullptr;
2460     SetNil(g->sp);
2461     longjmp(g->escapeInterpreter, 3);
2462     // hmm need to fix this to work only on main thread. //!!!
2463     // g->sp = g->gc->Stack()->slots - 1;
2464 
2465     return errReturn;
2466 }
2467 
2468 
2469 int prCanCallOS(struct VMGlobals* g, int numArgsPushed);
prCanCallOS(struct VMGlobals * g,int numArgsPushed)2470 int prCanCallOS(struct VMGlobals* g, int numArgsPushed) {
2471     PyrSlot* a = g->sp;
2472 
2473     SetBool(a, g->canCallOS);
2474 
2475     return errNone;
2476 }
2477 
2478 extern bool gGenerateTailCallByteCodes;
2479 
2480 int prGetTailCallOptimize(struct VMGlobals* g, int numArgsPushed);
prGetTailCallOptimize(struct VMGlobals * g,int numArgsPushed)2481 int prGetTailCallOptimize(struct VMGlobals* g, int numArgsPushed) {
2482     PyrSlot* a = g->sp;
2483 
2484     SetBool(a, gGenerateTailCallByteCodes);
2485 
2486     return errNone;
2487 }
2488 
2489 int prSetTailCallOptimize(struct VMGlobals* g, int numArgsPushed);
prSetTailCallOptimize(struct VMGlobals * g,int numArgsPushed)2490 int prSetTailCallOptimize(struct VMGlobals* g, int numArgsPushed) {
2491     // PyrSlot *a = g->sp - 1;
2492 
2493 #if TAILCALLOPTIMIZE
2494     PyrSlot* b = g->sp;
2495     if (IsTrue(b)) {
2496         gGenerateTailCallByteCodes = true;
2497     } else if (IsFalse(b)) {
2498         gGenerateTailCallByteCodes = false;
2499     } else
2500         return errWrongType;
2501 #endif
2502 
2503     return errNone;
2504 }
2505 
2506 
2507 int prTraceOn(struct VMGlobals* g, int numArgsPushed);
prTraceOn(struct VMGlobals * g,int numArgsPushed)2508 int prTraceOn(struct VMGlobals* g, int numArgsPushed) {
2509     PyrSlot* a;
2510 
2511     a = g->sp;
2512     gTraceInterpreter = IsTrue(a);
2513     return errNone;
2514 }
2515 
2516 int prKeywordError(struct VMGlobals* g, int numArgsPushed);
prKeywordError(struct VMGlobals * g,int numArgsPushed)2517 int prKeywordError(struct VMGlobals* g, int numArgsPushed) {
2518     PyrSlot* a;
2519 
2520     a = g->sp;
2521     gKeywordError = IsTrue(a);
2522     return errNone;
2523 }
2524 
2525 int prFunDef_NumArgs(struct VMGlobals* g, int numArgsPushed);
prFunDef_NumArgs(struct VMGlobals * g,int numArgsPushed)2526 int prFunDef_NumArgs(struct VMGlobals* g, int numArgsPushed) {
2527     PyrSlot* a;
2528     PyrMethodRaw* methraw;
2529 
2530     a = g->sp;
2531     methraw = METHRAW(slotRawBlock(a));
2532     SetInt(a, methraw->numargs);
2533     return errNone;
2534 }
2535 
2536 int prFunDef_NumVars(struct VMGlobals* g, int numArgsPushed);
prFunDef_NumVars(struct VMGlobals * g,int numArgsPushed)2537 int prFunDef_NumVars(struct VMGlobals* g, int numArgsPushed) {
2538     PyrSlot* a;
2539     PyrMethodRaw* methraw;
2540 
2541     a = g->sp;
2542     methraw = METHRAW(slotRawBlock(a));
2543     SetInt(a, methraw->numvars);
2544     return errNone;
2545 }
2546 
2547 int prFunDef_VarArgs(struct VMGlobals* g, int numArgsPushed);
prFunDef_VarArgs(struct VMGlobals * g,int numArgsPushed)2548 int prFunDef_VarArgs(struct VMGlobals* g, int numArgsPushed) {
2549     PyrSlot* a;
2550     PyrMethodRaw* methraw;
2551 
2552     a = g->sp;
2553     methraw = METHRAW(slotRawBlock(a));
2554     if (methraw->varargs) {
2555         SetTrue(a);
2556     } else {
2557         SetFalse(a);
2558     }
2559     return errNone;
2560 }
2561 
2562 
undefinedPrimitive(struct VMGlobals * g,int numArgsPushed)2563 int undefinedPrimitive(struct VMGlobals* g, int numArgsPushed) {
2564     error("A primitive was not bound. %d %d\n", g->primitiveIndex, gPrimitiveTable.size);
2565     dumpObject((PyrObject*)g->primitiveMethod);
2566     return errFailed;
2567 }
2568 
2569 void dumpByteCodes(PyrBlock* theBlock);
2570 
prDumpByteCodes(struct VMGlobals * g,int numArgsPushed)2571 int prDumpByteCodes(struct VMGlobals* g, int numArgsPushed) {
2572     PyrSlot* a;
2573 
2574     a = g->sp;
2575     dumpByteCodes(slotRawBlock(a));
2576     return errNone;
2577 }
2578 
prObjectPointsTo(struct VMGlobals * g,int numArgsPushed)2579 int prObjectPointsTo(struct VMGlobals* g, int numArgsPushed) {
2580     PyrSlot *a, *b, temp;
2581     PyrObject* obj;
2582     int i;
2583 
2584     a = g->sp - 1;
2585     b = g->sp;
2586 
2587     if (NotObj(a))
2588         slotCopy(a, &o_false);
2589     else {
2590         obj = slotRawObject(a);
2591         for (i = 0; i < obj->size; ++i) {
2592             getIndexedSlot(obj, &temp, i);
2593             if (SlotEq(&temp, b)) {
2594                 slotCopy(a, &o_true);
2595                 return errNone;
2596             }
2597         }
2598         slotCopy(a, &o_false);
2599     }
2600     return errNone;
2601 }
2602 
2603 
prObjectRespondsTo(struct VMGlobals * g,int numArgsPushed)2604 int prObjectRespondsTo(struct VMGlobals* g, int numArgsPushed) {
2605     PyrSlot *a, *b;
2606     PyrClass* classobj;
2607     PyrMethod* meth;
2608     PyrSymbol* selector;
2609     int index;
2610 
2611     a = g->sp - 1;
2612     b = g->sp;
2613 
2614     classobj = classOfSlot(a);
2615 
2616     if (IsSym(b)) {
2617         selector = slotRawSymbol(b);
2618         index = slotRawInt(&classobj->classIndex) + selector->u.index;
2619         meth = gRowTable[index];
2620         if (slotRawSymbol(&meth->name) != selector) {
2621             slotCopy(a, &o_false);
2622         } else {
2623             slotCopy(a, &o_true);
2624         }
2625     } else if (isKindOfSlot(b, class_array)) {
2626         int size = slotRawObject(b)->size;
2627         PyrSlot* slot = slotRawObject(b)->slots;
2628         for (int i = 0; i < size; ++i, ++slot) {
2629             if (NotSym(slot))
2630                 return errWrongType;
2631 
2632             selector = slotRawSymbol(slot);
2633             index = slotRawInt(&classobj->classIndex) + selector->u.index;
2634             meth = gRowTable[index];
2635             if (slotRawSymbol(&meth->name) != selector) {
2636                 slotCopy(a, &o_false);
2637                 return errNone;
2638             }
2639         }
2640         slotCopy(a, &o_true);
2641     } else
2642         return errWrongType;
2643     return errNone;
2644 }
2645 
2646 PyrMethod* GetFunctionCompileContext(VMGlobals* g);
GetFunctionCompileContext(VMGlobals * g)2647 PyrMethod* GetFunctionCompileContext(VMGlobals* g) {
2648     PyrClass* classobj;
2649     PyrSymbol *classsym, *contextsym;
2650     PyrMethod* meth;
2651     // lookup interpreter class
2652     classsym = getsym("Interpreter");
2653     classobj = classsym->u.classobj;
2654     if (!classobj) {
2655         error("There is no Interpreter class.\n");
2656         return nullptr;
2657     }
2658     // lookup functionCompileContext method
2659     contextsym = getsym("functionCompileContext");
2660     int index = slotRawInt(&classobj->classIndex) + contextsym->u.index;
2661     meth = gRowTable[index];
2662     if (!meth || slotRawSymbol(&meth->name) != contextsym) {
2663         error("compile context method 'functionCompileContext' not found.\n");
2664         return nullptr;
2665     }
2666     gCompilingClass = classobj;
2667     gCompilingMethod = meth;
2668     gCompilingBlock = (PyrBlock*)meth;
2669     return meth;
2670 }
2671 
2672 #if !SCPLAYER
prCompileString(struct VMGlobals * g,int numArgsPushed)2673 int prCompileString(struct VMGlobals* g, int numArgsPushed) {
2674     PyrSlot *a, *b;
2675     PyrString* string;
2676     PyrMethod* meth;
2677 
2678     a = g->sp - 1;
2679     b = g->sp;
2680 
2681     // check b is a string
2682     if (NotObj(b))
2683         return errWrongType;
2684     if (!isKindOf(slotRawObject(b), class_string))
2685         return errWrongType;
2686     string = slotRawString(b);
2687 
2688     gRootParseNode = nullptr;
2689     initParserPool();
2690     // assert(g->gc->SanityCheck());
2691     startLexerCmdLine(string->s, string->size);
2692     compileErrors = 0;
2693     compilingCmdLine = true;
2694     gCompilingVMGlobals = g;
2695     compilingCmdLineErrorWindow = false;
2696     // assert(g->gc->SanityCheck());
2697     parseFailed = yyparse();
2698     // assert(g->gc->SanityCheck());
2699     if (!parseFailed && gRootParseNode) {
2700         PyrSlot slotResult;
2701 
2702         meth = GetFunctionCompileContext(g);
2703         if (!meth)
2704             return errFailed;
2705 
2706         ((PyrBlockNode*)gRootParseNode)->mIsTopLevel = true;
2707 
2708         SetNil(&slotResult);
2709         COMPILENODE(gRootParseNode, &slotResult, true);
2710 
2711         if (NotObj(&slotResult) || slotRawObject(&slotResult)->classptr != class_fundef) {
2712             compileErrors++;
2713             error("Compile did not return a FunctionDef..\n");
2714         }
2715         if (compileErrors) {
2716             SetNil(a);
2717         } else {
2718             PyrBlock* block;
2719             PyrClosure* closure;
2720 
2721             block = slotRawBlock(&slotResult);
2722             // create a closure
2723             closure = (PyrClosure*)g->gc->New(2 * sizeof(PyrSlot), 0, obj_notindexed, false);
2724             closure->classptr = class_func;
2725             closure->size = 2;
2726             SetObject(&closure->block, block);
2727             slotCopy(&closure->context, &slotRawInterpreter(&g->process->interpreter)->context);
2728             SetObject(a, closure);
2729         }
2730     } else {
2731         if (parseFailed) {
2732             compileErrors++;
2733             error("Command line parse failed\n");
2734         } else {
2735             postfl("<nothing to do>\n");
2736         }
2737         SetNil(a);
2738     }
2739     finiLexer();
2740     freeParserPool();
2741 
2742     pyr_pool_compile->FreeAll();
2743     // flushErrors();
2744     compilingCmdLine = false;
2745 
2746     return !(parseFailed || compileErrors) ? errNone : errFailed;
2747 }
2748 #endif
2749 
2750 char sCodeStringIn[8192];
2751 char sCodeStringOut[8192];
2752 
2753 int prUGenCodeString(struct VMGlobals* g, int numArgsPushed);
prUGenCodeString(struct VMGlobals * g,int numArgsPushed)2754 int prUGenCodeString(struct VMGlobals* g, int numArgsPushed) {
2755     PyrSlot *aa, *bb, *cc, *dd, *ee;
2756     char* out = sCodeStringOut;
2757     char ugenPrefix[16];
2758     int err;
2759 
2760     aa = g->sp - 4; // code string
2761     bb = g->sp - 3; // ugen prefix
2762     ee = g->sp - 2; // isDecl
2763     cc = g->sp - 1; // input names
2764     dd = g->sp; // input value strings
2765 
2766     int ugenIndex;
2767     err = slotIntVal(bb, &ugenIndex);
2768     if (err)
2769         return err;
2770     if (!isKindOfSlot(cc, class_array) && !isKindOfSlot(cc, class_symbolarray))
2771         return errWrongType;
2772     if (!isKindOfSlot(dd, class_array))
2773         return errWrongType;
2774     bool isDecl = IsTrue(ee);
2775 
2776     PyrObject* inputNamesObj = slotRawObject(cc);
2777     PyrObject* inputStringsObj = slotRawObject(dd);
2778 
2779     sprintf(ugenPrefix, "u%d", ugenIndex);
2780     int ugenPrefixSize = strlen(ugenPrefix);
2781     PyrString* codeStringObj = slotRawString(aa);
2782     int codeStringSize = codeStringObj->size;
2783     if (codeStringSize > 8000) {
2784         error("input string too int.\n");
2785         return errFailed;
2786     }
2787     memcpy(sCodeStringIn, codeStringObj->s, codeStringSize);
2788     sCodeStringIn[codeStringSize] = 0;
2789 
2790     char* in = sCodeStringIn;
2791     int c;
2792     while ((c = *in++) != 0) {
2793         if (c == '@') {
2794             if (!isDecl) {
2795                 if (*in != '@') {
2796                     *out++ = 's';
2797                     *out++ = '-';
2798                     *out++ = '>';
2799                 } else
2800                     in++;
2801             }
2802             for (int j = 0; j < ugenPrefixSize; ++j) {
2803                 *out++ = ugenPrefix[j];
2804             }
2805         } else if (c == '$') {
2806             char name[64];
2807             int j = 0;
2808             do {
2809                 c = *in++;
2810                 if (c == 0)
2811                     break;
2812                 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) {
2813                     --in;
2814                     break;
2815                 }
2816                 name[j++] = c;
2817             } while (c);
2818 
2819             bool found = false;
2820             int nameSize = j;
2821             int slotIndex = -1;
2822             for (int j = 0; j < inputNamesObj->size; ++j) {
2823                 PyrSlot inputNameSlot;
2824                 getIndexedSlot(inputNamesObj, &inputNameSlot, j);
2825                 if (!IsSym(&inputNameSlot))
2826                     return errWrongType;
2827                 PyrSymbol* inputSym = slotRawSymbol(&inputNameSlot);
2828                 char* inputName = inputSym->name;
2829                 int inputNameSize = inputSym->length;
2830                 if (inputNameSize == nameSize && strncmp(inputName, name, nameSize) == 0) {
2831                     found = true;
2832                     slotIndex = j;
2833                     break;
2834                 }
2835             }
2836             if (slotIndex >= 0) {
2837                 PyrSlot* inputStringSlot = inputStringsObj->slots + slotIndex;
2838                 if (!isKindOfSlot(inputStringSlot, class_string))
2839                     return errWrongType;
2840                 PyrString* inputStringObj = slotRawString(inputStringSlot);
2841                 char* input = inputStringObj->s;
2842                 int inputStringSize = inputStringObj->size;
2843                 for (int j = 0; j < inputStringSize; ++j) {
2844                     *out++ = input[j];
2845                 }
2846             } else {
2847                 *out++ = '?';
2848                 *out++ = '?';
2849                 for (int j = 0; j < nameSize; ++j) {
2850                     *out++ = name[j];
2851                 }
2852                 *out++ = '?';
2853                 *out++ = '?';
2854             }
2855         } else {
2856             *out++ = c;
2857         }
2858         if (out - sCodeStringOut > 8000) {
2859             *out++ = '\n';
2860             *out++ = '.';
2861             *out++ = '.';
2862             *out++ = '.';
2863             *out++ = '\n';
2864             break;
2865         }
2866     }
2867     *out++ = 0;
2868     PyrString* outString = newPyrString(g->gc, sCodeStringOut, 0, true);
2869     SetObject(aa, outString);
2870 
2871     return errNone;
2872 }
2873 
2874 
2875 /*void threadSanity(VMGlobals *g, PyrThread *thread);
2876 void threadSanity(VMGlobals *g, PyrThread *thread)
2877 {
2878     int state;
2879     g->gc->numToScan = 1000000;
2880     doGC(g, 0);
2881     assert(g->gc->SanityCheck());
2882 
2883     state = slotRawInt(&thread->state);
2884     if (state == tYield) {
2885         if (!IsObj(&thread->method)) { error("thread method not an Object\n"); }
2886         else if (!isKindOf(slotRawObject(&thread->method), class_method)) { error("thread method not a Method\n"); }
2887         else if (slotRawObject(&thread->method)->gc_color == gcColor.gcFree) { error("thread method is FREE\n"); }
2888 
2889         if (!IsObj(&thread->block)) { error("thread block not an Object\n"); }
2890         else if (!isKindOf(slotRawObject(&thread->block), class_func)) { error("thread block not a Function\n"); }
2891         else if (slotRawObject(&thread->block)->gc_color == gcColor.gcFree) { error("thread block is FREE\n"); }
2892 
2893         if (IsObj(&thread->receiver) &slotRawObject(&& thread->receiver)->gc_color == gcColor.gcFree)
2894             { error("thread receiver is FREE\n"); }
2895 
2896         FrameSanity(thread->frame.uof);
2897 
2898         oldthread->method.uom = g->method;
2899         oldthread->block.uoblk = g->block;
2900         SetObject(&oldthread->frame, g->frame);
2901         slotRawInt(&oldthread->ip) = (int)g->ip;
2902         slotRawInt(&oldthread->sp) = (int)g->sp;
2903 
2904 
2905     } else if (state == tInit) {
2906     } else {
2907         postfl("bad state\n");
2908     }
2909 }*/
2910 
2911 
2912 PyrSymbol* s_prready;
2913 PyrSymbol* s_prrunnextthread;
2914 
2915 void switchToThread(VMGlobals* g, PyrThread* newthread, int oldstate, int* numArgsPushed);
switchToThread(VMGlobals * g,PyrThread * newthread,int oldstate,int * numArgsPushed)2916 void switchToThread(VMGlobals* g, PyrThread* newthread, int oldstate, int* numArgsPushed) {
2917     PyrThread* oldthread;
2918     PyrGC* gc;
2919     PyrFrame* frame;
2920 
2921 #if TAILCALLOPTIMIZE
2922     g->tailCall = 0; // ?? prevent a crash. is there a way to allow a TCO ?
2923 #endif
2924 
2925     oldthread = g->thread;
2926     if (newthread == oldthread)
2927         return;
2928     // postfl("->switchToThread %d %p -> %p\n", oldstate, oldthread, newthread);
2929     // post("->switchToThread from %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name,
2930     // g->slotRawSymbol(&method->name)->name); post("->stack %p  g->sp %p [%d]  g->top %p [%d]\n",
2931     // g->gc->Stack()->slots,
2932     // g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots); assert(g->gc->SanityCheck());
2933     // CallStackSanity(g, "switchToThreadA");
2934     // gcDumpInfo(g->gc);
2935     gc = g->gc;
2936 
2937     // save environment in oldthread
2938     PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1];
2939     slotCopy(&oldthread->environment, currentEnvironmentSlot);
2940     gc->GCWrite(oldthread, currentEnvironmentSlot);
2941 
2942     SetRaw(&oldthread->state, oldstate);
2943 
2944     if (oldstate == tDone) {
2945         SetObject(&oldthread->stack, gc->Stack());
2946         gc->ToWhite(gc->Stack());
2947         gc->Stack()->size = 0;
2948         gc->GCWrite(oldthread, gc->Stack());
2949         SetNil(&oldthread->method);
2950         SetNil(&oldthread->block);
2951         SetNil(&oldthread->receiver);
2952         SetNil(&oldthread->frame);
2953         SetRaw(&oldthread->ip, (void*)nullptr);
2954         SetRaw(&oldthread->sp, (void*)nullptr);
2955         SetRaw(&oldthread->numArgsPushed, 0);
2956         SetRaw(&oldthread->numpop, 0);
2957         SetNil(&oldthread->parent);
2958     } else if (oldstate == tInit) {
2959         SetObject(&oldthread->stack, gc->Stack());
2960         gc->ToWhite(gc->Stack());
2961         gc->Stack()->size = 0;
2962         gc->GCWrite(oldthread, gc->Stack());
2963         SetNil(&oldthread->method);
2964         SetNil(&oldthread->block);
2965         SetNil(&oldthread->receiver);
2966         SetNil(&oldthread->frame);
2967         SetRaw(&oldthread->ip, (void*)nullptr);
2968         SetRaw(&oldthread->sp, (void*)nullptr);
2969         SetRaw(&oldthread->numArgsPushed, 0);
2970         SetRaw(&oldthread->numpop, 0);
2971         SetNil(&oldthread->parent);
2972     } else {
2973         // save old thread's state
2974         SetObject(&oldthread->stack, gc->Stack());
2975         gc->ToWhite(gc->Stack());
2976         gc->Stack()->size = g->sp - gc->Stack()->slots + 1;
2977         // post("else %p %p\n", slotRawObject(&oldthread->stack), gc->Stack());
2978 
2979         SetObject(&oldthread->method, g->method);
2980         SetObject(&oldthread->block, g->block);
2981         SetObject(&oldthread->frame, g->frame);
2982         SetPtr(&oldthread->ip, g->ip);
2983         SetPtr(&oldthread->sp, g->sp);
2984         slotCopy(&oldthread->receiver, &g->receiver);
2985         SetRaw(&oldthread->numArgsPushed, *numArgsPushed);
2986         SetRaw(&oldthread->numpop, g->numpop);
2987 
2988         // gc->ToGrey(oldthread);
2989         if (gc->ObjIsBlack(oldthread)) {
2990             gc->GCWriteBlack(gc->Stack());
2991             gc->GCWriteBlack(g->method);
2992             gc->GCWriteBlack(g->block);
2993 
2994             frame = slotRawFrame(&oldthread->frame);
2995             gc->GCWriteBlack(frame);
2996 
2997             gc->GCWriteBlack(&g->receiver);
2998         }
2999     }
3000 
3001     // restore new thread's state
3002     g->thread = newthread;
3003     SetObject(&g->process->curThread, newthread);
3004     gc->GCWrite(g->process, newthread);
3005 
3006     gc->SetStack(slotRawObject(&newthread->stack));
3007     gc->ToBlack(gc->Stack());
3008     SetNil(&newthread->stack);
3009 
3010     g->method = slotRawMethod(&newthread->method);
3011     g->block = slotRawBlock(&newthread->block);
3012     g->frame = slotRawFrame(&newthread->frame);
3013     g->ip = (unsigned char*)slotRawPtr(&newthread->ip);
3014     g->sp = (PyrSlot*)slotRawPtr(&newthread->sp);
3015     slotCopy(&g->receiver, &newthread->receiver);
3016 
3017     g->rgen = (RGen*)(slotRawObject(&newthread->randData)->slots);
3018 
3019     *numArgsPushed = slotRawInt(&newthread->numArgsPushed);
3020 
3021     // these are perhaps unecessary because a thread may not
3022     // legally block within a C primitive
3023     g->numpop = slotRawInt(&newthread->numpop);
3024 
3025     g->execMethod = 99;
3026 
3027     // post("switchToThread ip %p\n", g->ip);
3028     // post(slotRawInt(&"switchToThread newthread->ip) %d\n", slotRawInt(&newthread->ip));
3029     // post(slotRawInt(&"switchToThread oldthread->ip) %d\n", slotRawInt(&oldthread->ip));
3030 
3031     // wipe out values which will become stale as new thread executes:
3032     SetNil(&newthread->method);
3033     SetNil(&newthread->block);
3034     SetNil(&newthread->frame);
3035     SetRaw(&newthread->ip, (void*)nullptr);
3036     SetRaw(&newthread->sp, (void*)nullptr);
3037     SetNil(&newthread->receiver);
3038 
3039     SetRaw(&newthread->state, tRunning);
3040 
3041 
3042     // set new environment
3043     slotCopy(currentEnvironmentSlot, &g->thread->environment);
3044     g->gc->GCWrite(g->classvars, currentEnvironmentSlot);
3045 
3046     // post("old thread %p stack %p\n", oldthread, slotRawObject(&oldthread->stack));
3047     // post("new thread %p stack %p\n", g->thread, slotRawObject(&g->thread->stack));
3048     // post("main thread %p stack %p\n", slotRawThread(&g->process->mainThread),
3049     // slotRawObject(&slotRawThread(&g->process->mainThread)->stack));
3050 
3051     // postfl("<-switchToThread\n");
3052     // post("<-stack %p  g->sp %p [%d]  g->top %p [%d]\n",
3053     //	g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots);
3054     // assert(g->gc->SanityCheck());
3055     // CallStackSanity(g, "switchToThreadB");
3056     // post("switchToThread ip2 %p\n", g->ip);
3057 }
3058 
3059 void initPyrThread(VMGlobals* g, PyrThread* thread, PyrSlot* func, int stacksize, PyrInt32Array* rgenArray,
3060                    double beats, double seconds, PyrSlot* clock, bool runGC);
initPyrThread(VMGlobals * g,PyrThread * thread,PyrSlot * func,int stacksize,PyrInt32Array * rgenArray,double beats,double seconds,PyrSlot * clock,bool runGC)3061 void initPyrThread(VMGlobals* g, PyrThread* thread, PyrSlot* func, int stacksize, PyrInt32Array* rgenArray,
3062                    double beats, double seconds, PyrSlot* clock, bool runGC) {
3063     PyrObject* array;
3064     PyrGC* gc = g->gc;
3065 
3066     slotCopy(&thread->func, func);
3067     gc->GCWrite(thread, func);
3068 
3069     array = newPyrArray(gc, stacksize, 0, runGC);
3070     SetObject(&thread->stack, array);
3071     gc->GCWriteNew(thread, array); // we know array is white so we can use GCWriteNew
3072 
3073     SetInt(&thread->state, tInit);
3074 
3075     SetPtr(&thread->ip, nullptr);
3076     SetPtr(&thread->sp, nullptr);
3077 
3078     SetObject(&thread->randData, rgenArray);
3079     gc->GCWrite(thread, rgenArray);
3080 
3081     SetFloat(&thread->beats, beats);
3082     SetFloat(&thread->seconds, seconds);
3083     SetInt(&thread->numArgsPushed, 0);
3084     SetInt(&thread->numpop, 0);
3085 
3086     if (IsNil(clock)) {
3087         SetObject(&thread->clock, s_systemclock->u.classobj);
3088     } else {
3089         slotCopy(&thread->clock, clock);
3090         gc->GCWrite(thread, clock);
3091     }
3092 
3093     PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1];
3094     slotCopy(&thread->environment, currentEnvironmentSlot);
3095     gc->GCWrite(thread, currentEnvironmentSlot);
3096 
3097     if (g->process) { // check we're not just starting up
3098         slotCopy(&thread->executingPath, &g->process->nowExecutingPath);
3099         gc->GCWrite(thread, &g->process->nowExecutingPath);
3100     }
3101 
3102     SetInt(&thread->stackSize, stacksize);
3103 }
3104 
3105 extern PyrSymbol* s_prstart;
3106 
3107 int prThreadInit(struct VMGlobals* g, int numArgsPushed);
prThreadInit(struct VMGlobals * g,int numArgsPushed)3108 int prThreadInit(struct VMGlobals* g, int numArgsPushed) {
3109     PyrSlot *a, *b, *c;
3110     int stacksize, err;
3111     PyrThread* thread;
3112 
3113     // postfl("->prThreadInit\n");
3114     // assert(g->gc->SanityCheck());
3115     // CallStackSanity(g, "prThreadInit");
3116     a = g->sp - 2; // thread
3117     b = g->sp - 1; // function
3118     c = g->sp; // stacksize
3119 
3120     thread = slotRawThread(a);
3121 
3122     if (NotObj(b) || !isKindOf(slotRawObject(b), class_func)) {
3123         error("Thread function arg not a Function.\n");
3124         return errWrongType;
3125     }
3126 
3127     err = slotIntVal(c, &stacksize);
3128     if (err)
3129         return err;
3130 
3131     stacksize = std::max(stacksize, EVALSTACKDEPTH);
3132 
3133     double beats, seconds;
3134     err = slotDoubleVal(&g->thread->beats, &beats);
3135     if (err)
3136         return err;
3137     err = slotDoubleVal(&g->thread->seconds, &seconds);
3138     if (err)
3139         return err;
3140 
3141     initPyrThread(g, thread, b, stacksize, (PyrInt32Array*)(slotRawObject(&g->thread->randData)), beats, seconds,
3142                   &g->thread->clock, true);
3143 
3144     // postfl("<-prThreadInit\n");
3145     // assert(g->gc->SanityCheck());
3146     // CallStackSanity(g, "<prThreadInit");
3147     return errNone;
3148 }
3149 
3150 int prThreadRandSeed(struct VMGlobals* g, int numArgsPushed);
prThreadRandSeed(struct VMGlobals * g,int numArgsPushed)3151 int prThreadRandSeed(struct VMGlobals* g, int numArgsPushed) {
3152     PyrSlot* a = g->sp - 1; // thread
3153     PyrSlot* b = g->sp; // rand seed
3154 
3155     PyrThread* thread = slotRawThread(a);
3156 
3157     int32 seed;
3158     int err = slotIntVal(b, &seed);
3159     if (err)
3160         return err;
3161 
3162     PyrInt32Array* rgenArray = newPyrInt32Array(g->gc, 4, 0, true);
3163     rgenArray->size = 4;
3164     ((RGen*)(rgenArray->i))->init(seed);
3165 
3166     if (thread == g->thread) {
3167         g->rgen = (RGen*)(rgenArray->i);
3168     }
3169     SetObject(&thread->randData, rgenArray);
3170     g->gc->GCWriteNew(thread, rgenArray); // we know rgenArray is white so we can use GCWriteNew
3171 
3172     return errNone;
3173 }
3174 
3175 int prThreadGetRandData(struct VMGlobals* g, int numArgsPushed);
prThreadGetRandData(struct VMGlobals * g,int numArgsPushed)3176 int prThreadGetRandData(struct VMGlobals* g, int numArgsPushed) {
3177     PyrSlot* a = g->sp; // thread
3178 
3179     PyrThread* thread = slotRawThread(a);
3180 
3181     RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots;
3182 
3183     PyrInt32Array* rgenArray = newPyrInt32Array(g->gc, 4, 0, false);
3184     rgenArray->size = 3;
3185 
3186     rgenArray->i[0] = rgen->s1;
3187     rgenArray->i[1] = rgen->s2;
3188     rgenArray->i[2] = rgen->s3;
3189 
3190     SetObject(a, rgenArray);
3191     return errNone;
3192 }
3193 
3194 int prThreadSetRandData(struct VMGlobals* g, int numArgsPushed);
prThreadSetRandData(struct VMGlobals * g,int numArgsPushed)3195 int prThreadSetRandData(struct VMGlobals* g, int numArgsPushed) {
3196     PyrSlot* a = g->sp - 1; // thread
3197     PyrSlot* b = g->sp; // rand data array
3198 
3199     if (!isKindOfSlot(b, class_int32array))
3200         return errWrongType;
3201     if (slotRawObject(b)->size < 3)
3202         return errWrongType;
3203 
3204     PyrThread* thread = slotRawThread(a);
3205 
3206     RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots;
3207 
3208     PyrInt32Array* rgenArray = (PyrInt32Array*)slotRawObject(b);
3209 
3210     rgen->s1 = rgenArray->i[0];
3211     rgen->s2 = rgenArray->i[1];
3212     rgen->s3 = rgenArray->i[2];
3213 
3214     return errNone;
3215 }
3216 
3217 #if 0
3218 int32 timeseed();
3219 
3220 int transformMainThreadToRoutine(VMGlobals *g)
3221 {
3222 	PyrProcess* process = g->process;
3223 	if (g->thread != process->mainThread.uot) return errFailed;
3224 	//if (g->thread != process->curThread.uot) return errFailed;
3225 
3226 	PyrThread* curthread = (PyrThread*)slotRawObject(&process->mainThread);
3227 
3228 	// create a new main thread
3229 	PyrThread* newthread = (PyrThread*)instantiateObject(g->gc, class_thread, 0, true, false);
3230 
3231 	PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false);
3232 	rgenArray->size = 4;
3233 	((RGen*)(rgenArray->i))->init(timeseed());
3234 
3235 	PyrSlot clockSlot;
3236 	SetObject(&clockSlot, s_systemclock->u.classobj);
3237 	initPyrThread(g, newthread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false);
3238 	slotRawInt(&newthread->sp) = (int)slotRawObject(&newthread->stack)->slots - 1;
3239 	SetObject(&process->mainThread, newthread);
3240 	g->gc->GCWrite(process, newthread);
3241 
3242 	curthread->classptr = class_routine;
3243 	PyrSlot *cmdFunc = &process->interpreter.uoi->cmdFunc;
3244 	slotCopy(&curthread->func,cmdFunc);
3245 	g->gc->GCWrite(curthread, cmdFunc);
3246 
3247 	return errNone;
3248 }
3249 
3250 void schedAdd(VMGlobals *g, PyrObject* inQueue, double inSeconds, PyrSlot* inTask);
3251 #endif
3252 
3253 
3254 int prRoutineYield(struct VMGlobals* g, int numArgsPushed);
prRoutineYield(struct VMGlobals * g,int numArgsPushed)3255 int prRoutineYield(struct VMGlobals* g, int numArgsPushed) {
3256     PyrSlot value;
3257 
3258     // postfl("->prRoutineYield %p\n", g->thread);
3259     // assert(g->gc->SanityCheck());
3260     // CallStackSanity(g, "prRoutineYield");
3261     // postfl("->numArgsPushed %d\n", numArgsPushed);
3262 
3263     slotCopy(&value, g->sp);
3264 
3265     if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3266         error("yield was called outside of a Routine.\n");
3267         return errFailed;
3268     }
3269 
3270     PyrThread* parent = slotRawThread(&g->thread->parent);
3271     SetNil(&g->thread->parent);
3272     slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3273     // debugf("yield from thread %p to parent %p\n", g->thread, slotRawThread(&g->thread->parent));
3274     switchToThread(g, parent, tSuspended, &numArgsPushed);
3275 
3276     // on the other side of the looking glass, put the yielded value on the stack as the result..
3277     slotCopy((g->sp - numArgsPushed + 1), &value);
3278 
3279     // postfl("<-numArgsPushed %d\n", numArgsPushed);
3280     // postfl("<-prRoutineYield\n");
3281     // assert(g->gc->SanityCheck());
3282     // CallStackSanity(g, "<prRoutineYield");
3283     return errNone;
3284 }
3285 
3286 int prRoutineAlwaysYield(struct VMGlobals* g, int numArgsPushed);
prRoutineAlwaysYield(struct VMGlobals * g,int numArgsPushed)3287 int prRoutineAlwaysYield(struct VMGlobals* g, int numArgsPushed) {
3288     PyrSlot value;
3289 
3290     // postfl("->prRoutineAlwaysYield ip %p\n", g->ip);
3291     // assert(g->gc->SanityCheck());
3292     // CallStackSanity(g, "prRoutineAlwaysYield");
3293     if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3294         error("alwaysYield was called outside of a Routine.\n");
3295         return errFailed;
3296     }
3297 
3298     slotCopy(&value, g->sp);
3299     slotCopy(&g->thread->terminalValue, &value);
3300     g->gc->GCWrite(g->thread, g->sp);
3301 
3302     PyrThread* parent = slotRawThread(&g->thread->parent);
3303     SetNil(&g->thread->parent);
3304     slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3305     // post("alwaysYield from thread %p to parent %p\n", g->thread, parent);
3306     switchToThread(g, parent, tDone, &numArgsPushed);
3307 
3308     // on the other side of the looking glass, put the yielded value on the stack as the result..
3309     slotCopy((g->sp - numArgsPushed + 1), &value);
3310 
3311     // postfl("<-prRoutineAlwaysYield ip %p\n", g->ip);
3312     // assert(g->gc->SanityCheck());
3313     // CallStackSanity(g, "<prRoutineAlwaysYield");
3314     return errNone;
3315 }
3316 
3317 int prRoutineResume(struct VMGlobals* g, int numArgsPushed);
prRoutineResume(struct VMGlobals * g,int numArgsPushed)3318 int prRoutineResume(struct VMGlobals* g, int numArgsPushed) {
3319     PyrSlot *a, *b, threadSlot, value;
3320     PyrThread* thread;
3321     int state;
3322 
3323     // assert(g->gc->SanityCheck());
3324     // CallStackSanity(g, "prRoutineResume");
3325     a = g->sp - 1;
3326     b = g->sp;
3327 
3328     thread = slotRawThread(a);
3329     state = slotRawInt(&thread->state);
3330     // postfl("->prRoutineResume %d\n", state);
3331 
3332     slotCopy(&thread->oldExecutingPath, &g->process->nowExecutingPath);
3333     slotCopy(&g->process->nowExecutingPath, &thread->executingPath);
3334     if (state == tInit) {
3335         slotCopy(&threadSlot, a);
3336         slotCopy(&value, b);
3337 
3338         // post("g->thread %p\n", g->thread);
3339         // post("thread %p\n", thread);
3340         SetObject(&thread->parent, g->thread);
3341         g->gc->GCWrite(thread, g->thread);
3342 
3343         slotCopy(&thread->beats, &g->thread->beats);
3344         slotCopy(&thread->seconds, &g->thread->seconds);
3345         slotCopy(&thread->clock, &g->thread->clock);
3346         g->gc->GCWrite(thread, &g->thread->beats);
3347         g->gc->GCWrite(thread, &g->thread->seconds);
3348         g->gc->GCWrite(thread, &g->thread->clock);
3349 
3350         // postfl("start into thread %p from parent %p\n", thread, g->thread);
3351         switchToThread(g, thread, tSuspended, &numArgsPushed);
3352 
3353         // set stack
3354         // post("set stack %p %p\n", g->sp, g->gc->Stack()->slots - 1);
3355         g->sp = g->gc->Stack()->slots - 1;
3356         slotCopy((++g->sp), &threadSlot);
3357         slotCopy(&g->receiver, &threadSlot);
3358         slotCopy((++g->sp), &value);
3359 
3360         sendMessage(g, s_prstart, 2);
3361     } else if (state == tSuspended) {
3362         if (IsNil(&thread->parent)) {
3363             SetObject(&thread->parent, g->thread);
3364         }
3365         g->gc->GCWrite(thread, g->thread);
3366 
3367         slotCopy(&thread->beats, &g->thread->beats);
3368         slotCopy(&thread->seconds, &g->thread->seconds);
3369         slotCopy(&thread->clock, &g->thread->clock);
3370         g->gc->GCWrite(thread, &g->thread->beats);
3371         g->gc->GCWrite(thread, &g->thread->seconds);
3372         g->gc->GCWrite(thread, &g->thread->clock);
3373 
3374         slotCopy(&value, b);
3375         // debugf("resume into thread %p from parent %p\n", thread, g->thread);
3376         switchToThread(g, thread, tSuspended, &numArgsPushed);
3377         // on the other side of the looking glass, put the yielded value on the stack as the result..
3378         slotCopy((g->sp - numArgsPushed + 1), &value);
3379     } else if (state == tDone) {
3380         slotCopy(a, &thread->terminalValue);
3381     } else if (state == tRunning) {
3382         error("Tried to resume the running thread.\n");
3383         return errFailed;
3384     } else {
3385         error("Thread in strange state: %d\n", state);
3386         return errFailed;
3387     }
3388     // postfl("<-prRoutineResume\n");
3389     // CallStackSanity(g);
3390     return errNone;
3391 }
3392 
3393 int prRoutineReset(struct VMGlobals* g, int numArgsPushed);
prRoutineReset(struct VMGlobals * g,int numArgsPushed)3394 int prRoutineReset(struct VMGlobals* g, int numArgsPushed) {
3395     PyrThread* thread;
3396     int state;
3397 
3398     // assert(g->gc->SanityCheck());
3399     // CallStackSanity(g, "prRoutineReset");
3400     thread = slotRawThread(g->sp);
3401     state = slotRawInt(&thread->state);
3402     // post("->prRoutineReset %d\n", state);
3403     if (state == tSuspended) {
3404         SetRaw(&thread->state, tInit);
3405         slotRawObject(&thread->stack)->size = 0;
3406         SetNil(&thread->method);
3407         SetNil(&thread->block);
3408         SetNil(&thread->receiver);
3409         SetNil(&thread->frame);
3410         SetRaw(&thread->ip, (void*)nullptr);
3411         SetRaw(&thread->sp, (void*)nullptr);
3412         SetRaw(&thread->numArgsPushed, 0);
3413         SetRaw(&thread->numpop, 0);
3414         SetNil(&thread->parent);
3415     } else if (state == tDone) {
3416         SetRaw(&thread->state, tInit);
3417         slotRawObject(&thread->stack)->size = 0;
3418         SetNil(&thread->method);
3419         SetNil(&thread->block);
3420         SetNil(&thread->receiver);
3421         SetNil(&thread->frame);
3422         SetRaw(&thread->ip, (void*)nullptr);
3423         SetRaw(&thread->sp, (void*)nullptr);
3424         SetRaw(&thread->numArgsPushed, 0);
3425         SetRaw(&thread->numpop, 0);
3426         SetNil(&thread->parent);
3427     } else if (state == tInit) {
3428         // do nothing
3429     } else if (state == tRunning) {
3430         error("A Routine cannot reset itself except by yieldAndReset.\n");
3431         return errFailed;
3432     } else {
3433         error("Routine in unknown state. %d\n", state);
3434         return errFailed;
3435     }
3436     // assert(g->gc->SanityCheck());
3437     // CallStackSanity(g, "<prRoutineReset");
3438     return errNone;
3439 }
3440 
3441 int prRoutineStop(struct VMGlobals* g, int numArgsPushed);
prRoutineStop(struct VMGlobals * g,int numArgsPushed)3442 int prRoutineStop(struct VMGlobals* g, int numArgsPushed) {
3443     PyrThread* thread;
3444     int state;
3445     // post("->prRoutineStop\n");
3446     // assert(g->gc->SanityCheck());
3447     // CallStackSanity(g, "prRoutineStop");
3448 
3449     thread = slotRawThread(g->sp);
3450     state = slotRawInt(&thread->state);
3451 
3452 
3453     if (state == tSuspended || state == tInit) {
3454         SetNil(&g->thread->terminalValue);
3455         SetRaw(&thread->state, tDone);
3456         slotRawObject(&thread->stack)->size = 0;
3457     } else if (state == tDone) {
3458         // do nothing
3459     } else if (state == tRunning) {
3460         error("Do not call .stop from within the Routine.\n");
3461         post("A Routine should stop itself using nil.alwaysYield.\n");
3462         return errFailed;
3463     } else {
3464         error("Routine in unknown state. %d\n", state);
3465         return errFailed;
3466     }
3467     // assert(g->gc->SanityCheck());
3468     // CallStackSanity(g, "<prRoutineStop");
3469     return errNone;
3470 }
3471 
3472 
3473 int prRoutineYieldAndReset(struct VMGlobals* g, int numArgsPushed);
prRoutineYieldAndReset(struct VMGlobals * g,int numArgsPushed)3474 int prRoutineYieldAndReset(struct VMGlobals* g, int numArgsPushed) {
3475     PyrSlot *a, *b, value;
3476     int state;
3477 
3478     // post("->prRoutineYieldAndReset\n");
3479     // assert(g->gc->SanityCheck());
3480     // CallStackSanity(g, "prRoutineYieldAndReset");
3481     a = g->sp - 1;
3482     b = g->sp;
3483 
3484     if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3485         error("yieldAndReset was called outside of a Routine.\n");
3486         return errFailed;
3487     }
3488     /*if (!slotRawThread(&g->thread->parent)) {
3489         error ("yieldAndReset was called from a thread with no parent.\n");
3490         return errFailed;
3491     }*/
3492     slotCopy(&value, a);
3493 
3494     if (IsFalse(b))
3495         state = tSuspended;
3496     else
3497         state = tInit;
3498 
3499     PyrThread* parent = slotRawThread(&g->thread->parent);
3500     SetNil(&g->thread->parent);
3501     switchToThread(g, parent, state, &numArgsPushed);
3502     // on the other side of the looking glass, put the yielded value on the stack as the result..
3503     slotCopy((g->sp - numArgsPushed + 1), &value);
3504 
3505     // slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3506 
3507     // post("<-prRoutineYieldAndReset\n");
3508     // assert(g->gc->SanityCheck());
3509     // CallStackSanity(g, "prRoutineYieldAndReset");
3510     return errNone;
3511 }
3512 
3513 
3514 bool gBlork = false;
3515 
3516 int prBlork(struct VMGlobals* g, int numArgsPushed);
prBlork(struct VMGlobals * g,int numArgsPushed)3517 int prBlork(struct VMGlobals* g, int numArgsPushed) {
3518     PyrSlot* a;
3519 
3520     a = g->sp;
3521     if (IsTrue(a))
3522         gBlork = true;
3523     else
3524         gBlork = false;
3525 
3526     return errNone;
3527 }
3528 
3529 int prOverwriteMsg(struct VMGlobals* g, int numArgsPushed);
prOverwriteMsg(struct VMGlobals * g,int numArgsPushed)3530 int prOverwriteMsg(struct VMGlobals* g, int numArgsPushed) {
3531     PyrSlot* a = g->sp;
3532     PyrString* string = newPyrString(g->gc, overwriteMsg.c_str(), 0, false);
3533     SetObject(a, string);
3534     return errNone;
3535 }
3536 
prAppClockSchedNotify(struct VMGlobals * g,int numArgsPushed)3537 int prAppClockSchedNotify(struct VMGlobals* g, int numArgsPushed) {
3538     // NOTE: the _AppClock_SchedNotify primitive shall be redefined by language clients
3539     // if they wish to respond to AppClock scheduling notifications
3540     return errNone;
3541 }
3542 
3543 enum { includePaths, excludePaths };
3544 
prLanguageConfig_getLibraryPaths(struct VMGlobals * g,int numArgsPushed,int pathType)3545 static int prLanguageConfig_getLibraryPaths(struct VMGlobals* g, int numArgsPushed, int pathType) {
3546     PyrSlot* result = g->sp;
3547 
3548     typedef SC_LanguageConfig::DirVector DirVector;
3549 
3550     const DirVector& dirVector =
3551         (pathType == includePaths) ? gLanguageConfig->includedDirectories() : gLanguageConfig->excludedDirectories();
3552 
3553     size_t numberOfPaths = dirVector.size();
3554     PyrObject* resultArray = newPyrArray(g->gc, numberOfPaths, 0, true);
3555     SetObject(result, resultArray); // this is okay here as we don't use the receiver
3556 
3557     for (size_t i = 0; i != numberOfPaths; ++i) {
3558         const std::string& utf8_path = SC_Codecvt::path_to_utf8_str(dirVector[i]);
3559         PyrString* pyrString = newPyrString(g->gc, utf8_path.c_str(), 0, true);
3560         SetObject(resultArray->slots + i, pyrString);
3561         g->gc->GCWriteNew(resultArray, pyrString); // we know pyrString is white so we can use GCWriteNew
3562         resultArray->size++;
3563     }
3564     return errNone;
3565 }
3566 
prLanguageConfig_getIncludePaths(struct VMGlobals * g,int numArgsPushed)3567 static int prLanguageConfig_getIncludePaths(struct VMGlobals* g, int numArgsPushed) {
3568     return prLanguageConfig_getLibraryPaths(g, numArgsPushed, includePaths);
3569 }
3570 
prLanguageConfig_getExcludePaths(struct VMGlobals * g,int numArgsPushed)3571 static int prLanguageConfig_getExcludePaths(struct VMGlobals* g, int numArgsPushed) {
3572     return prLanguageConfig_getLibraryPaths(g, numArgsPushed, excludePaths);
3573 }
3574 
prLanguageConfig_addLibraryPath(struct VMGlobals * g,int numArgsPushed,int pathType)3575 static int prLanguageConfig_addLibraryPath(struct VMGlobals* g, int numArgsPushed, int pathType) {
3576     PyrSlot* removeString = g->sp;
3577 
3578     char path[MAXPATHLEN];
3579     bool error = slotStrVal(removeString, path, MAXPATHLEN);
3580     if (error)
3581         return errWrongType;
3582 
3583     const bfs::path& native_path = SC_Codecvt::utf8_str_to_path(path);
3584     if (pathType == includePaths)
3585         gLanguageConfig->addIncludedDirectory(native_path);
3586     else
3587         gLanguageConfig->addExcludedDirectory(native_path);
3588     return errNone;
3589 }
3590 
prLanguageConfig_addIncludePath(struct VMGlobals * g,int numArgsPushed)3591 static int prLanguageConfig_addIncludePath(struct VMGlobals* g, int numArgsPushed) {
3592     return prLanguageConfig_addLibraryPath(g, numArgsPushed, includePaths);
3593 }
3594 
prLanguageConfig_addExcludePath(struct VMGlobals * g,int numArgsPushed)3595 static int prLanguageConfig_addExcludePath(struct VMGlobals* g, int numArgsPushed) {
3596     return prLanguageConfig_addLibraryPath(g, numArgsPushed, excludePaths);
3597 }
3598 
prLanguageConfig_removeLibraryPath(struct VMGlobals * g,int numArgsPushed,int pathType)3599 static int prLanguageConfig_removeLibraryPath(struct VMGlobals* g, int numArgsPushed, int pathType) {
3600     PyrSlot* dirString = g->sp;
3601 
3602     char path[MAXPATHLEN];
3603     bool error = slotStrVal(dirString, path, MAXPATHLEN);
3604     if (error)
3605         return errWrongType;
3606 
3607     const bfs::path& native_path = SC_Codecvt::utf8_str_to_path(path);
3608     if (pathType == includePaths)
3609         gLanguageConfig->removeIncludedDirectory(native_path);
3610     else
3611         gLanguageConfig->removeExcludedDirectory(native_path);
3612     return errNone;
3613 }
3614 
prLanguageConfig_removeIncludePath(struct VMGlobals * g,int numArgsPushed)3615 static int prLanguageConfig_removeIncludePath(struct VMGlobals* g, int numArgsPushed) {
3616     return prLanguageConfig_removeLibraryPath(g, numArgsPushed, includePaths);
3617 }
3618 
prLanguageConfig_removeExcludePath(struct VMGlobals * g,int numArgsPushed)3619 static int prLanguageConfig_removeExcludePath(struct VMGlobals* g, int numArgsPushed) {
3620     return prLanguageConfig_removeLibraryPath(g, numArgsPushed, excludePaths);
3621 }
3622 
prLanguageConfig_getCurrentConfigPath(struct VMGlobals * g,int numArgsPushed)3623 static int prLanguageConfig_getCurrentConfigPath(struct VMGlobals* g, int numArgsPushed) {
3624     PyrSlot* a = g->sp;
3625     const std::string& config_path = SC_Codecvt::path_to_utf8_str(gLanguageConfig->getConfigPath());
3626     PyrString* str = newPyrString(g->gc, config_path.c_str(), 0, false);
3627     if (str->size == 0) {
3628         SetNil(a);
3629     } else {
3630         SetObject(a, str);
3631     }
3632 
3633     return errNone;
3634 }
3635 
prLanguageConfig_writeConfigFile(struct VMGlobals * g,int numArgsPushed)3636 static int prLanguageConfig_writeConfigFile(struct VMGlobals* g, int numArgsPushed) {
3637     PyrSlot* fileString = g->sp;
3638     bfs::path config_path;
3639 
3640     if (NotNil(fileString)) {
3641         char path[MAXPATHLEN];
3642         bool error = slotStrVal(fileString, path, MAXPATHLEN);
3643         if (error)
3644             return errWrongType;
3645 
3646         config_path = SC_Codecvt::utf8_str_to_path(path);
3647     } else {
3648         config_path = SC_Codecvt::path_to_utf8_str(gLanguageConfig->getConfigPath());
3649         if (config_path.empty())
3650             config_path = SC_Filesystem::instance().getDirectory(SC_Filesystem::DirName::UserConfig)
3651                 / SCLANG_YAML_CONFIG_FILENAME;
3652     }
3653 
3654     if (!gLanguageConfig->writeLibraryConfigYAML(config_path))
3655         return errFailed;
3656     else
3657         return errNone;
3658 }
3659 
prLanguageConfig_getPostInlineWarnings(struct VMGlobals * g,int numArgsPushed)3660 static int prLanguageConfig_getPostInlineWarnings(struct VMGlobals* g, int numArgsPushed) {
3661     PyrSlot* result = g->sp;
3662     SetBool(result, SC_LanguageConfig::getPostInlineWarnings());
3663     return errNone;
3664 }
3665 
prLanguageConfig_setPostInlineWarnings(struct VMGlobals * g,int numArgsPushed)3666 static int prLanguageConfig_setPostInlineWarnings(struct VMGlobals* g, int numArgsPushed) {
3667     PyrSlot* arg = g->sp;
3668 
3669     if (IsTrue(arg))
3670         SC_LanguageConfig::setPostInlineWarnings(true);
3671     else if (IsFalse(arg))
3672         SC_LanguageConfig::setPostInlineWarnings(false);
3673     else
3674         return errWrongType;
3675 
3676     return errNone;
3677 }
3678 
3679 
prVersionMajor(struct VMGlobals * g,int numArgsPushed)3680 static int prVersionMajor(struct VMGlobals* g, int numArgsPushed) {
3681     PyrSlot* result = g->sp;
3682     SetInt(result, SC_VersionMajor);
3683     return errNone;
3684 }
3685 
prVersionMinor(struct VMGlobals * g,int numArgsPushed)3686 static int prVersionMinor(struct VMGlobals* g, int numArgsPushed) {
3687     PyrSlot* result = g->sp;
3688     SetInt(result, SC_VersionMinor);
3689     return errNone;
3690 }
3691 
prVersionPatch(struct VMGlobals * g,int numArgsPushed)3692 static int prVersionPatch(struct VMGlobals* g, int numArgsPushed) {
3693     PyrSlot* result = g->sp;
3694     SetInt(result, SC_VersionPatch);
3695     return errNone;
3696 }
3697 
prVersionTweak(struct VMGlobals * g,int numArgsPushed)3698 static int prVersionTweak(struct VMGlobals* g, int numArgsPushed) {
3699     PyrSlot* result = g->sp;
3700     SetObject(result, newPyrString(g->gc, SC_VersionTweak, 0, 1));
3701     return errNone;
3702 }
3703 
3704 
3705 #define PRIMGROWSIZE 480
3706 PrimitiveTable gPrimitiveTable;
3707 
initPrimitiveTable()3708 void initPrimitiveTable() {
3709     int i;
3710     gPrimitiveTable.maxsize = PRIMGROWSIZE;
3711     gPrimitiveTable.size = 0;
3712     // pyrmalloc:
3713     // lifetime: runtime. primitives are reloaded when library is compiled.
3714     gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef));
3715     MEMFAIL(gPrimitiveTable.table);
3716     for (i = 0; i < gPrimitiveTable.maxsize; ++i) {
3717         gPrimitiveTable.table[i].func = undefinedPrimitive;
3718         gPrimitiveTable.table[i].name = s_none;
3719         gPrimitiveTable.table[i].base = 0;
3720         gPrimitiveTable.table[i].numArgs = 0;
3721         gPrimitiveTable.table[i].varArgs = 0;
3722         gPrimitiveTable.table[i].keyArgs = 0;
3723     }
3724 }
3725 
growPrimitiveTable(int newsize)3726 void growPrimitiveTable(int newsize) {
3727     PrimitiveDef* oldtable;
3728     int i, oldsize;
3729     // postfl("growPrimitiveTable %d %d\n", oldsize, newsize);
3730     oldtable = gPrimitiveTable.table;
3731     oldsize = gPrimitiveTable.maxsize;
3732     gPrimitiveTable.maxsize = newsize;
3733     // pyrmalloc:
3734     // lifetime: runtime. primitives are reloaded when library is compiled.
3735     gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef));
3736     MEMFAIL(gPrimitiveTable.table);
3737     memcpy(gPrimitiveTable.table, oldtable, oldsize * sizeof(PrimitiveDef));
3738     for (i = oldsize; i < gPrimitiveTable.maxsize; ++i) {
3739         gPrimitiveTable.table[i].func = undefinedPrimitive;
3740         gPrimitiveTable.table[i].name = s_none;
3741         gPrimitiveTable.table[i].base = 0;
3742         gPrimitiveTable.table[i].numArgs = 0;
3743         gPrimitiveTable.table[i].varArgs = 0;
3744         gPrimitiveTable.table[i].keyArgs = 0;
3745     }
3746     pyr_pool_runtime->Free(oldtable);
3747 }
3748 
definePrimitive(int base,int index,const char * name,PrimitiveHandler handler,int numArgs,int varArgs)3749 int definePrimitive(int base, int index, const char* name, PrimitiveHandler handler, int numArgs, int varArgs) {
3750     int tableIndex;
3751     PyrSymbol* sym;
3752 
3753     if (name[0] != '_') {
3754         error("*** Primitive Name must begin with an underscore ***\n");
3755         postfl("name: '%s' index: %d\n", name, index);
3756         return -1;
3757     }
3758     tableIndex = base + index;
3759     if (tableIndex < 0) {
3760         error("*** Negative Primitive Index ***\n");
3761         postfl("name: '%s' index: %d\n", name, tableIndex);
3762         return -1;
3763     }
3764     if (tableIndex >= gPrimitiveTable.maxsize) {
3765         growPrimitiveTable(tableIndex + PRIMGROWSIZE);
3766     }
3767     if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) {
3768         error("*** Duplicate Primitive Index ***\n");
3769         postfl("name: '%s' index: %d\n", name, tableIndex);
3770         return -1;
3771     }
3772     sym = getsym(name);
3773     gPrimitiveTable.table[tableIndex].func = handler;
3774     gPrimitiveTable.table[tableIndex].name = sym;
3775     gPrimitiveTable.table[tableIndex].base = base;
3776     gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3777     gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3778     gPrimitiveTable.table[tableIndex].keyArgs = 0;
3779     if (tableIndex > gPrimitiveTable.size)
3780         gPrimitiveTable.size = tableIndex;
3781     sym->u.index = tableIndex;
3782     return tableIndex;
3783 }
3784 
definePrimitiveWithKeys(int base,int index,const char * name,PrimitiveHandler handler,PrimitiveWithKeysHandler keyhandler,int numArgs,int varArgs)3785 int definePrimitiveWithKeys(int base, int index, const char* name, PrimitiveHandler handler,
3786                             PrimitiveWithKeysHandler keyhandler, int numArgs, int varArgs) {
3787     int tableIndex;
3788     PyrSymbol* sym;
3789 
3790     if (name[0] != '_') {
3791         error("*** Primitive Name must begin with an underscore ***\n");
3792         postfl("name: '%s' index: %d\n", name, index);
3793         return -1;
3794     }
3795     tableIndex = base + index;
3796     if (tableIndex < 0) {
3797         error("*** Negative Primitive Index ***\n");
3798         postfl("name: '%s' index: %d\n", name, tableIndex);
3799         return -1;
3800     }
3801     if (tableIndex + 1 >= gPrimitiveTable.maxsize) {
3802         growPrimitiveTable(tableIndex + PRIMGROWSIZE);
3803     }
3804     if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) {
3805         error("*** Duplicate Primitive Index ***\n");
3806         postfl("name: '%s' index: %d\n", name, tableIndex);
3807         return -1;
3808     }
3809     sym = getsym(name);
3810     gPrimitiveTable.table[tableIndex].func = handler;
3811     gPrimitiveTable.table[tableIndex].name = sym;
3812     gPrimitiveTable.table[tableIndex].base = base;
3813     gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3814     gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3815     gPrimitiveTable.table[tableIndex].keyArgs = 1;
3816     sym->u.index = tableIndex;
3817 
3818     tableIndex++;
3819     gPrimitiveTable.table[tableIndex].func = (PrimitiveHandler)keyhandler;
3820     gPrimitiveTable.table[tableIndex].name = sym;
3821     gPrimitiveTable.table[tableIndex].base = base;
3822     gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3823     gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3824     gPrimitiveTable.table[tableIndex].keyArgs = 1;
3825     if (tableIndex > gPrimitiveTable.size)
3826         gPrimitiveTable.size = tableIndex;
3827     return tableIndex;
3828 }
3829 
nextPrimitiveIndex()3830 int nextPrimitiveIndex() { return gPrimitiveTable.size + 1; }
3831 
3832 
doPrimitive(VMGlobals * g,PyrMethod * meth,int numArgsPushed)3833 void doPrimitive(VMGlobals* g, PyrMethod* meth, int numArgsPushed) {
3834 #ifdef GC_SANITYCHECK
3835     g->gc->SanityCheck();
3836 #endif
3837 
3838     // post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name,
3839     // slotRawSymbol(&meth->name)->name);
3840 
3841     PyrMethodRaw* methraw = METHRAW(meth);
3842     int primIndex = methraw->specialIndex;
3843 
3844     PrimitiveDef* def = gPrimitiveTable.table + primIndex;
3845     int numArgsNeeded = def->numArgs;
3846     int diff = numArgsNeeded - numArgsPushed;
3847 
3848     if (diff != 0) { // incorrect num of args
3849         if (diff > 0) { // not enough args
3850             PyrSlot* pslot = g->sp;
3851             PyrSlot* qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
3852             for (int m = 0; m < diff; ++m)
3853                 slotCopy(++pslot, ++qslot);
3854 
3855             g->sp += diff;
3856         } else if (def->varArgs) { // has var args
3857             numArgsNeeded = numArgsPushed;
3858         } else {
3859             g->sp += diff; // remove excess args
3860         }
3861     }
3862     g->numpop = numArgsNeeded - 1;
3863     g->primitiveIndex = primIndex - def->base;
3864     g->primitiveMethod = meth;
3865     g->args = g->sp - numArgsNeeded;
3866     int err;
3867     try {
3868 #ifdef GC_SANITYCHECK
3869         g->gc->SanityCheck();
3870 #endif
3871         err = (*def->func)(g, numArgsNeeded);
3872 #ifdef GC_SANITYCHECK
3873         g->gc->SanityCheck();
3874 #endif
3875     } catch (std::exception& ex) {
3876         g->lastExceptions[g->thread] = std::make_pair(std::current_exception(), meth);
3877         err = errException;
3878     } catch (...) {
3879         g->lastExceptions[g->thread] = std::make_pair(nullptr, meth);
3880         err = errException;
3881     }
3882     if (err <= errNone)
3883         g->sp -= g->numpop;
3884     else {
3885         // post("primitive failed %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name,
3886         // slotRawSymbol(&meth->name)->name);
3887         SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3888         SetInt(&g->thread->primitiveError, err);
3889         executeMethod(g, meth, numArgsNeeded);
3890     }
3891 #ifdef GC_SANITYCHECK
3892     g->gc->SanityCheck();
3893 #endif
3894 }
3895 
doPrimitiveWithKeys(VMGlobals * g,PyrMethod * meth,int allArgsPushed,int numKeyArgsPushed)3896 void doPrimitiveWithKeys(VMGlobals* g, PyrMethod* meth, int allArgsPushed, int numKeyArgsPushed) {
3897     int i, j, m, diff, err;
3898     PyrSlot *pslot, *qslot;
3899     int numArgsNeeded, numArgsPushed;
3900 
3901 #ifdef GC_SANITYCHECK
3902     g->gc->SanityCheck();
3903 #endif
3904     // post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name,
3905     // slotRawSymbol(&meth->name)->name); printf("doPrimitive %s:%s\n",
3906     // slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3907 
3908     PyrMethodRaw* methraw = METHRAW(meth);
3909     int primIndex = methraw->specialIndex;
3910     PrimitiveDef* def = gPrimitiveTable.table + primIndex;
3911     g->primitiveIndex = primIndex - def->base;
3912     g->primitiveMethod = meth;
3913 
3914     if (def->keyArgs && numKeyArgsPushed) {
3915         g->numpop = allArgsPushed - 1;
3916         try {
3917             err = ((PrimitiveWithKeysHandler)def[1].func)(g, allArgsPushed, numKeyArgsPushed);
3918         } catch (std::exception& ex) {
3919             g->lastExceptions[g->thread] = std::make_pair(std::current_exception(), meth);
3920             err = errException;
3921         } catch (...) {
3922             g->lastExceptions[g->thread] = std::make_pair(nullptr, meth);
3923             err = errException;
3924         }
3925         if (err <= errNone)
3926             g->sp -= g->numpop;
3927         else {
3928             // post("primerr %d\n", err);
3929             SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3930             SetInt(&g->thread->primitiveError, err);
3931             executeMethodWithKeys(g, meth, allArgsPushed, numKeyArgsPushed);
3932         }
3933     } else {
3934         numArgsNeeded = def->numArgs;
3935         numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1);
3936 
3937         if (numKeyArgsPushed) {
3938             // evacuate keyword args to separate area
3939             pslot = keywordstack + (numKeyArgsPushed << 1);
3940             qslot = g->sp + 1;
3941             for (m = 0; m < numKeyArgsPushed; ++m) {
3942                 slotCopy(--pslot, --qslot);
3943                 slotCopy(--pslot, --qslot);
3944             }
3945         }
3946 
3947         diff = numArgsNeeded - numArgsPushed;
3948         if (diff != 0) { // incorrect num of args
3949             if (diff > 0) { // not enough args
3950                 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3951                 pslot = g->sp - diff;
3952                 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
3953                 for (m = 0; m < diff; ++m)
3954                     slotCopy(++pslot, ++qslot);
3955             } else if (def->varArgs) { // has var args
3956                 numArgsNeeded = numArgsPushed;
3957                 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3958             } else {
3959                 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3960             }
3961         }
3962 
3963         // do keyword lookup:
3964         if (numKeyArgsPushed && methraw->posargs) {
3965             PyrSymbol **name0, **name;
3966             PyrSlot *key, *vars;
3967             name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
3968             key = keywordstack;
3969             vars = g->sp - numArgsNeeded + 1;
3970             for (i = 0; i < numKeyArgsPushed; ++i, key += 2) {
3971                 name = name0;
3972                 for (j = 1; j < methraw->posargs; ++j, ++name) {
3973                     if (*name == slotRawSymbol(key)) {
3974                         slotCopy(&vars[j], &key[1]);
3975                         goto found;
3976                     }
3977                 }
3978                 if (gKeywordError) {
3979                     post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name,
3980                          slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3981                 }
3982             found:;
3983             }
3984         }
3985         g->numpop = numArgsNeeded - 1;
3986         try {
3987             err = (*def->func)(g, numArgsNeeded);
3988         } catch (std::exception& ex) {
3989             g->lastExceptions[g->thread] = std::make_pair(std::current_exception(), meth);
3990             err = errException;
3991         } catch (...) {
3992             g->lastExceptions[g->thread] = std::make_pair(nullptr, meth);
3993             err = errException;
3994         }
3995         if (err <= errNone)
3996             g->sp -= g->numpop;
3997         else {
3998             // post("primerr %d\n", err);
3999             SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
4000             SetInt(&g->thread->primitiveError, err);
4001             executeMethod(g, meth, numArgsNeeded);
4002         }
4003     }
4004 #ifdef GC_SANITYCHECK
4005     g->gc->SanityCheck();
4006 #endif
4007 }
4008 
initPrimitives()4009 void initPrimitives() {
4010     int base, index;
4011 
4012     initPrimitiveTable();
4013 
4014     // unary operators
4015     base = nextPrimitiveIndex();
4016     definePrimitive(base, opNeg, "_Neg", doSpecialUnaryArithMsg, 1, 0);
4017     definePrimitive(base, opBitNot, "_BitNot", doSpecialUnaryArithMsg, 1, 0);
4018     definePrimitive(base, opAbs, "_Abs", doSpecialUnaryArithMsg, 1, 0);
4019     definePrimitive(base, opAsFloat, "_AsFloat", doSpecialUnaryArithMsg, 1, 0);
4020     definePrimitive(base, opAsInteger, "_AsInteger", doSpecialUnaryArithMsg, 1, 0);
4021     definePrimitive(base, opCeil, "_Ceil", doSpecialUnaryArithMsg, 1, 0); // 5
4022     definePrimitive(base, opFloor, "_Floor", doSpecialUnaryArithMsg, 1, 0);
4023     definePrimitive(base, opFrac, "_Frac", doSpecialUnaryArithMsg, 1, 0);
4024     definePrimitive(base, opSign, "_Sign", doSpecialUnaryArithMsg, 1, 0);
4025     definePrimitive(base, opSquared, "_Squared", doSpecialUnaryArithMsg, 1, 0);
4026     definePrimitive(base, opCubed, "_Cubed", doSpecialUnaryArithMsg, 1, 0); // 10
4027     definePrimitive(base, opSqrt, "_Sqrt", doSpecialUnaryArithMsg, 1, 0);
4028     definePrimitive(base, opExp, "_Exp", doSpecialUnaryArithMsg, 1, 0);
4029     definePrimitive(base, opRecip, "_Recip", doSpecialUnaryArithMsg, 1, 0);
4030     definePrimitive(base, opMIDICPS, "_MIDICPS", doSpecialUnaryArithMsg, 1, 0);
4031     definePrimitive(base, opCPSMIDI, "_CPSMIDI", doSpecialUnaryArithMsg, 1, 0); // 15
4032 
4033     definePrimitive(base, opMIDIRatio, "_MIDIRatio", doSpecialUnaryArithMsg, 1, 0);
4034     definePrimitive(base, opRatioMIDI, "_RatioMIDI", doSpecialUnaryArithMsg, 1, 0);
4035     definePrimitive(base, opDbAmp, "_DbAmp", doSpecialUnaryArithMsg, 1, 0);
4036     definePrimitive(base, opAmpDb, "_AmpDb", doSpecialUnaryArithMsg, 1, 0);
4037     definePrimitive(base, opOctCPS, "_OctCPS", doSpecialUnaryArithMsg, 1, 0);
4038     definePrimitive(base, opCPSOct, "_CPSOct", doSpecialUnaryArithMsg, 1, 0);
4039     definePrimitive(base, opLog, "_Log", doSpecialUnaryArithMsg, 1, 0);
4040     definePrimitive(base, opLog2, "_Log2", doSpecialUnaryArithMsg, 1, 0);
4041     definePrimitive(base, opLog10, "_Log10", doSpecialUnaryArithMsg, 1, 0);
4042     definePrimitive(base, opSin, "_Sin", doSpecialUnaryArithMsg, 1, 0);
4043     definePrimitive(base, opCos, "_Cos", doSpecialUnaryArithMsg, 1, 0);
4044     definePrimitive(base, opTan, "_Tan", doSpecialUnaryArithMsg, 1, 0);
4045     definePrimitive(base, opArcSin, "_ArcSin", doSpecialUnaryArithMsg, 1, 0);
4046     definePrimitive(base, opArcCos, "_ArcCos", doSpecialUnaryArithMsg, 1, 0);
4047     definePrimitive(base, opArcTan, "_ArcTan", doSpecialUnaryArithMsg, 1, 0);
4048     definePrimitive(base, opSinH, "_SinH", doSpecialUnaryArithMsg, 1, 0);
4049     definePrimitive(base, opCosH, "_CosH", doSpecialUnaryArithMsg, 1, 0);
4050     definePrimitive(base, opTanH, "_TanH", doSpecialUnaryArithMsg, 1, 0);
4051     definePrimitive(base, opRand, "_Rand", doSpecialUnaryArithMsg, 1, 0);
4052     definePrimitive(base, opRand2, "_Rand2", doSpecialUnaryArithMsg, 1, 0);
4053     definePrimitive(base, opLinRand, "_LinRand", doSpecialUnaryArithMsg, 1, 0);
4054     definePrimitive(base, opBiLinRand, "_BiLinRand", doSpecialUnaryArithMsg, 1, 0);
4055 
4056     definePrimitive(base, opSum3Rand, "_Sum3Rand", doSpecialUnaryArithMsg, 1, 0);
4057     //	definePrimitive(base, opExpRand, "_ExpRand", doSpecialUnaryArithMsg, 1, 0);
4058     //	definePrimitive(base, opBiExpRand, "_BiExpRand", doSpecialUnaryArithMsg, 1, 0);
4059     //	definePrimitive(base, opGammaRand, "_GammaRand", doSpecialUnaryArithMsg, 1, 0);
4060     //	definePrimitive(base, opGaussRand, "_GaussRand", doSpecialUnaryArithMsg, 1, 0);
4061     //	definePrimitive(base, opPoiRand, "_PoiRand", doSpecialUnaryArithMsg, 1, 0);
4062 
4063     definePrimitive(base, opDistort, "_Distort", doSpecialUnaryArithMsg, 1, 0);
4064     definePrimitive(base, opSoftClip, "_SoftClip", doSpecialUnaryArithMsg, 1, 0);
4065     definePrimitive(base, opCoin, "_Coin", doSpecialUnaryArithMsg, 1, 0);
4066 
4067     definePrimitive(base, opRectWindow, "_RectWindow", doSpecialUnaryArithMsg, 1, 0);
4068     definePrimitive(base, opHanWindow, "_HanWindow", doSpecialUnaryArithMsg, 1, 0);
4069     definePrimitive(base, opWelchWindow, "_WelchWindow", doSpecialUnaryArithMsg, 1, 0);
4070     definePrimitive(base, opTriWindow, "_TriWindow", doSpecialUnaryArithMsg, 1, 0);
4071 
4072     definePrimitive(base, opSCurve, "_SCurve", doSpecialUnaryArithMsg, 1, 0);
4073     definePrimitive(base, opRamp, "_Ramp", doSpecialUnaryArithMsg, 1, 0);
4074 
4075     definePrimitive(base, opDigitValue, "_DigitValue", doSpecialUnaryArithMsg, 1, 0);
4076 
4077 
4078     // binary operators
4079     base = nextPrimitiveIndex();
4080     definePrimitive(base, opAdd, "_Add", prAddNum, 2, 0);
4081     definePrimitive(base, opSub, "_Sub", prSubNum, 2, 0);
4082     definePrimitive(base, opMul, "_Mul", prMulNum, 2, 0);
4083 
4084     definePrimitive(base, opIDiv, "_IDiv", prSpecialBinaryArithMsg, 3, 0);
4085     definePrimitive(base, opFDiv, "_FDiv", prSpecialBinaryArithMsg, 3, 0);
4086     definePrimitive(base, opMod, "_Mod", prSpecialBinaryArithMsg, 3, 0);
4087     definePrimitive(base, opEQ, "_EQ", prSpecialBinaryArithMsg, 3, 0);
4088     definePrimitive(base, opNE, "_NE", prSpecialBinaryArithMsg, 3, 0);
4089     definePrimitive(base, opLT, "_LT", prSpecialBinaryArithMsg, 3, 0);
4090     definePrimitive(base, opGT, "_GT", prSpecialBinaryArithMsg, 3, 0);
4091     definePrimitive(base, opLE, "_LE", prSpecialBinaryArithMsg, 3, 0);
4092     definePrimitive(base, opGE, "_GE", prSpecialBinaryArithMsg, 3, 0);
4093     // definePrimitive(base, opIdentical, "_Identical", prSpecialBinaryArithMsg, 3, 0);
4094     // definePrimitive(base, opNotIdentical, "_NotIdentical", prSpecialBinaryArithMsg, 3, 0);
4095 
4096     definePrimitive(base, opMin, "_Min", prSpecialBinaryArithMsg, 3, 0);
4097     definePrimitive(base, opMax, "_Max", prSpecialBinaryArithMsg, 3, 0);
4098     definePrimitive(base, opBitAnd, "_BitAnd", prSpecialBinaryArithMsg, 3, 0);
4099     definePrimitive(base, opBitOr, "_BitOr", prSpecialBinaryArithMsg, 3, 0);
4100     definePrimitive(base, opBitXor, "_BitXor", prSpecialBinaryArithMsg, 3, 0);
4101     definePrimitive(base, opLCM, "_LCM", prSpecialBinaryArithMsg, 3, 0);
4102     definePrimitive(base, opGCD, "_GCD", prSpecialBinaryArithMsg, 3, 0);
4103     definePrimitive(base, opRound, "_Round", prSpecialBinaryArithMsg, 3, 0);
4104     definePrimitive(base, opRoundUp, "_RoundUp", prSpecialBinaryArithMsg, 3, 0);
4105     definePrimitive(base, opTrunc, "_Trunc", prSpecialBinaryArithMsg, 3, 0);
4106     definePrimitive(base, opAtan2, "_Atan2", prSpecialBinaryArithMsg, 3, 0);
4107     definePrimitive(base, opHypot, "_Hypot", prSpecialBinaryArithMsg, 3, 0);
4108     definePrimitive(base, opHypotx, "_HypotApx", prSpecialBinaryArithMsg, 3, 0);
4109     definePrimitive(base, opPow, "_Pow", prSpecialBinaryArithMsg, 3, 0);
4110     definePrimitive(base, opShiftLeft, "_ShiftLeft", prSpecialBinaryArithMsg, 3, 0);
4111     definePrimitive(base, opShiftRight, "_ShiftRight", prSpecialBinaryArithMsg, 3, 0);
4112     definePrimitive(base, opUnsignedShift, "_UnsignedShift", prSpecialBinaryArithMsg, 3, 0);
4113     definePrimitive(base, opFill, "_Fill", prSpecialBinaryArithMsg, 3, 0);
4114     definePrimitive(base, opRing1, "_Ring1", prSpecialBinaryArithMsg, 3, 0); // a * (b + 1) == a * b + a
4115     definePrimitive(base, opRing2, "_Ring2", prSpecialBinaryArithMsg, 3, 0); // a * b + a + b
4116     definePrimitive(base, opRing3, "_Ring3", prSpecialBinaryArithMsg, 3, 0); // a*a*b
4117     definePrimitive(base, opRing4, "_Ring4", prSpecialBinaryArithMsg, 3, 0); // a*a*b - a*b*b
4118     definePrimitive(base, opDifSqr, "_DifSqr", prSpecialBinaryArithMsg, 3, 0); // a*a - b*b
4119     definePrimitive(base, opSumSqr, "_SumSqr", prSpecialBinaryArithMsg, 3, 0); // a*a + b*b
4120     definePrimitive(base, opSqrSum, "_SqrSum", prSpecialBinaryArithMsg, 3, 0); // (a + b)^2
4121     definePrimitive(base, opSqrDif, "_SqrDif", prSpecialBinaryArithMsg, 3, 0); // (a - b)^2
4122     definePrimitive(base, opAbsDif, "_AbsDif", prSpecialBinaryArithMsg, 3, 0); // abs(a - b)
4123     definePrimitive(base, opThresh, "_Thresh", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b)
4124     definePrimitive(base, opAMClip, "_AMClip", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b)
4125     definePrimitive(base, opScaleNeg, "_ScaleNeg", prSpecialBinaryArithMsg, 3, 0); // a < 0 ? a*b : a
4126     definePrimitive(base, opClip2, "_Clip2", prSpecialBinaryArithMsg, 3, 0);
4127     definePrimitive(base, opFold2, "_Fold2", prSpecialBinaryArithMsg, 3, 0);
4128     definePrimitive(base, opWrap2, "_Wrap2", prSpecialBinaryArithMsg, 3, 0);
4129     definePrimitive(base, opExcess, "_Excess", prSpecialBinaryArithMsg, 3, 0);
4130     definePrimitive(base, opFirstArg, "_FirstArg", prSpecialBinaryArithMsg, 3, 0);
4131     definePrimitive(base, opRandRange, "_RandRange", prSpecialBinaryArithMsg, 3, 0);
4132     definePrimitive(base, opExpRandRange, "_ExpRandRange", prSpecialBinaryArithMsg, 3, 0);
4133 
4134     // general primitives
4135     base = nextPrimitiveIndex();
4136     index = 0;
4137     definePrimitive(base, index++, "_Halt", haltInterpreter, 1, 0);
4138     definePrimitive(base, index++, "_InstVarAt", instVarAt, 2, 0);
4139     definePrimitive(base, index++, "_InstVarPut", instVarPut, 3, 0);
4140     definePrimitive(base, index++, "_InstVarSize", instVarSize, 1, 0);
4141     definePrimitive(base, index++, "_ObjectHash", objectHash, 1, 0);
4142     definePrimitive(base, index++, "_ObjectClass", objectClass, 1, 0);
4143     definePrimitive(base, index++, "_BasicNew", basicNew, 2, 0);
4144     definePrimitive(base, index++, "_BasicNewClear", basicNewClear, 2, 0);
4145     definePrimitive(base, index++, "_BasicNewCopyArgsToInstVars", basicNewCopyArgsToInstanceVars, 1, 1);
4146     // definePrimitive(base, index++, "_BasicNewCopyArgsByName", basicNewCopyArgsByName, 1, 1);
4147 
4148     definePrimitiveWithKeys(base, index, "_FunctionValue", blockValue, blockValueWithKeys, 1, 1);
4149     index += 2;
4150     definePrimitiveWithKeys(base, index, "_FunctionValueEnvir", blockValueEnvir, blockValueEnvirWithKeys, 1, 1);
4151     index += 2;
4152 
4153     definePrimitive(base, index++, "_FunctionValueArray", blockValueArray, 1, 1);
4154     definePrimitive(base, index++, "_FunctionValueArrayEnvir", blockValueArrayEnvir, 1, 1);
4155     definePrimitive(base, index++, "_FunctionDefAsFunction", prFunctionDefAsFunction, 1, 0);
4156     definePrimitive(base, index++, "_FunctionDefDumpContexts", prFunctionDefDumpContexts, 1, 0);
4157     definePrimitive(base, index++, "_FunctionDefIsClosed", prFunctionDefIsClosed, 1, 0);
4158     definePrimitive(base, index++, "_FunctionDefIsWithinClosed", prFunctionDefIsWithinClosed, 1, 0);
4159 
4160     definePrimitive(base, index++, "_ObjectIsKindOf", objectIsKindOf, 2, 0);
4161     definePrimitive(base, index++, "_ObjectIsMemberOf", objectIsMemberOf, 2, 0);
4162     definePrimitive(base, index++, "_ObjectDump", objectDump, 1, 0);
4163     definePrimitive(base, index++, "_TotalFree", prTotalFree, 1, 0);
4164     definePrimitive(base, index++, "_LargestFreeBlock", prLargestFreeBlock, 1, 0);
4165 
4166     definePrimitive(base, index++, "_GCInfo", dumpGCinfo, 1, 0);
4167     definePrimitive(base, index++, "_GCDumpGrey", dumpGCdumpGrey, 1, 0);
4168     definePrimitive(base, index++, "_GCDumpSet", dumpGCdumpSet, 2, 0);
4169     definePrimitive(base, index++, "_GCSanity", prGCSanity, 1, 0);
4170 #if GCDEBUG
4171     definePrimitive(base, index++, "_TraceAllPathsTo", prTraceAllPathsTo, 1, 0);
4172     definePrimitive(base, index++, "_TraceAnyPathsTo", prTraceAnyPathsTo, 1, 0);
4173     definePrimitive(base, index++, "_TraceAnyPathToAllInstancesOf", prTraceAnyPathToAllInstancesOf, 1, 0);
4174 #endif
4175 
4176     definePrimitive(base, index++, "_Identical", objectIdentical, 2, 0);
4177     definePrimitive(base, index++, "_NotIdentical", objectNotIdentical, 2, 0);
4178     definePrimitiveWithKeys(base, index, "_ObjectPerform", objectPerform, objectPerformWithKeys, 2, 1);
4179     index += 2;
4180     definePrimitive(base, index++, "_ObjectPerformList", objectPerformList, 2, 1);
4181     definePrimitiveWithKeys(base, index, "_SuperPerform", objectSuperPerform, objectSuperPerformWithKeys, 2, 1);
4182     index += 2;
4183     definePrimitive(base, index++, "_SuperPerformList", objectSuperPerformList, 2, 1);
4184     definePrimitive(base, index++, "_ObjectPerformMsg", objectPerformSelList, 2, 0);
4185     // definePrimitive(base, index++, "_ArrayPerformMsg", arrayPerformMsg, 1, 1);
4186     definePrimitive(base, index++, "_ObjectString", prObjectString, 1, 0);
4187     definePrimitive(base, index++, "_Float_AsStringPrec", prFloat_AsStringPrec, 2, 0);
4188     definePrimitive(base, index++, "_ObjectCompileString", prAsCompileString, 1, 0);
4189     definePrimitive(base, index++, "_ClassString", prClassString, 1, 0);
4190     definePrimitive(base, index++, "_PostString", prPostString, 1, 0);
4191     definePrimitive(base, index++, "_PostLine", prPostLine, 1, 0);
4192     definePrimitive(base, index++, "_HostDebugger", prDebugger, 1, 0);
4193     definePrimitive(base, index++, "_Trace", prTraceOn, 1, 0);
4194     definePrimitive(base, index++, "_CanCallOS", prCanCallOS, 1, 0);
4195     definePrimitive(base, index++, "_KeywordError", prKeywordError, 1, 0);
4196     definePrimitive(base, index++, "_GetTailCallOptimize", prGetTailCallOptimize, 1, 0);
4197     definePrimitive(base, index++, "_SetTailCallOptimize", prSetTailCallOptimize, 2, 0);
4198 
4199 
4200     definePrimitive(base, index++, "_PrimitiveError", prPrimitiveError, 1, 0);
4201     definePrimitive(base, index++, "_PrimitiveErrorString", prPrimitiveErrorString, 1, 0);
4202     definePrimitive(base, index++, "_DumpStack", prDumpStack, 1, 0);
4203     definePrimitive(base, index++, "_DumpDetailedBackTrace", prDumpDetailedBackTrace, 1, 0);
4204     definePrimitive(base, index++, "_StackDepth", prStackDepth, 1, 0);
4205     definePrimitive(base, index++, "_PrimName", prPrimName, 1, 0);
4206     definePrimitive(base, index++, "_ObjectShallowCopy", prObjectShallowCopy, 1, 0);
4207     definePrimitive(base, index++, "_ObjectCopyImmutable", prObjectCopyImmutable, 1, 0);
4208     definePrimitive(base, index++, "_ObjectCopyRange", prObjectCopyRange, 3, 0);
4209     definePrimitive(base, index++, "_ObjectCopySeries", prObjectCopySeries, 4, 0);
4210     definePrimitive(base, index++, "_ObjectPointsTo", prObjectPointsTo, 2, 0);
4211     definePrimitive(base, index++, "_ObjectRespondsTo", prObjectRespondsTo, 2, 0);
4212     definePrimitive(base, index++, "_ObjectIsMutable", prObjectIsMutable, 1, 0);
4213     definePrimitive(base, index++, "_ObjectIsPermanent", prObjectIsPermanent, 1, 0);
4214     definePrimitive(base, index++, "_ObjectDeepFreeze", prDeepFreeze, 1, 0);
4215     definePrimitive(base, index++, "_ObjectDeepCopy", prDeepCopy, 1, 0);
4216 
4217 #if !SCPLAYER
4218     definePrimitive(base, index++, "_CompileExpression", prCompileString, 2, 0);
4219 #endif
4220     definePrimitive(base, index++, "_GetBackTrace", prGetBackTrace, 1, 0);
4221     definePrimitive(base, index++, "_DumpBackTrace", prDumpBackTrace, 1, 0);
4222     definePrimitive(base, index++, "_DumpByteCodes", prDumpByteCodes, 1, 0);
4223 
4224     definePrimitive(base, index++, "_AllClasses", prAllClasses, 1, 0);
4225     definePrimitive(base, index++, "_DumpClassSubtree", prPostClassTree, 1, 0);
4226 
4227     //	definePrimitive(base, index++, "_TabletTracking", prTabletTracking, 1, 0);
4228 
4229     definePrimitive(base, index++, "_FunDef_NumArgs", prFunDef_NumArgs, 1, 0);
4230     definePrimitive(base, index++, "_FunDef_NumVars", prFunDef_NumVars, 1, 0);
4231     definePrimitive(base, index++, "_FunDef_VarArgs", prFunDef_VarArgs, 1, 0);
4232 
4233     definePrimitive(base, index++, "_Thread_Init", prThreadInit, 3, 0);
4234     definePrimitive(base, index++, "_Thread_RandSeed", prThreadRandSeed, 2, 0);
4235     definePrimitive(base, index++, "_Thread_GetRandData", prThreadGetRandData, 1, 0);
4236     definePrimitive(base, index++, "_Thread_SetRandData", prThreadSetRandData, 2, 0);
4237     //	definePrimitive(base, index++, "_ThreadRun", prThreadRun, 2, 0);
4238     //	definePrimitive(base, index++, "_RunNextThread", prRunNextThread, 1, 0);
4239     definePrimitive(base, index++, "_RoutineYield", prRoutineYield, 1, 0);
4240     definePrimitive(base, index++, "_RoutineAlwaysYield", prRoutineAlwaysYield, 1, 0);
4241     definePrimitive(base, index++, "_RoutineResume", prRoutineResume, 2, 0);
4242     definePrimitive(base, index++, "_RoutineReset", prRoutineReset, 1, 0);
4243     definePrimitive(base, index++, "_RoutineYieldAndReset", prRoutineYieldAndReset, 2, 0);
4244     definePrimitive(base, index++, "_RoutineStop", prRoutineStop, 1, 0);
4245 
4246     //	definePrimitive(base, index++, "_IsDemo", prIsDemo, 1, 0);
4247     definePrimitive(base, index++, "_Blork", prBlork, 1, 0);
4248     definePrimitive(base, index++, "_UGenCodeString", prUGenCodeString, 5, 0);
4249     definePrimitive(base, index++, "_MainOverwriteMsg", prOverwriteMsg, 1, 0);
4250 
4251     definePrimitive(base, index++, "_AppClock_SchedNotify", prAppClockSchedNotify, 1, 0);
4252     definePrimitive(base, index++, "_LanguageConfig_getCurrentConfigPath", prLanguageConfig_getCurrentConfigPath, 1, 0);
4253     definePrimitive(base, index++, "_LanguageConfig_getIncludePaths", prLanguageConfig_getIncludePaths, 1, 0);
4254     definePrimitive(base, index++, "_LanguageConfig_getExcludePaths", prLanguageConfig_getExcludePaths, 1, 0);
4255     definePrimitive(base, index++, "_LanguageConfig_addIncludePath", prLanguageConfig_addIncludePath, 2, 0);
4256     definePrimitive(base, index++, "_LanguageConfig_addExcludePath", prLanguageConfig_addExcludePath, 2, 0);
4257     definePrimitive(base, index++, "_LanguageConfig_removeIncludePath", prLanguageConfig_removeIncludePath, 2, 0);
4258     definePrimitive(base, index++, "_LanguageConfig_removeExcludePath", prLanguageConfig_removeExcludePath, 2, 0);
4259     definePrimitive(base, index++, "_LanguageConfig_writeConfigFile", prLanguageConfig_writeConfigFile, 2, 0);
4260     definePrimitive(base, index++, "_LanguageConfig_getPostInlineWarnings", prLanguageConfig_getPostInlineWarnings, 1,
4261                     0);
4262     definePrimitive(base, index++, "_LanguageConfig_setPostInlineWarnings", prLanguageConfig_setPostInlineWarnings, 2,
4263                     0);
4264 
4265     definePrimitive(base, index++, "_SC_VersionMajor", prVersionMajor, 1, 0);
4266     definePrimitive(base, index++, "_SC_VersionMinor", prVersionMinor, 1, 0);
4267     definePrimitive(base, index++, "_SC_VersionPatch", prVersionPatch, 1, 0);
4268     definePrimitive(base, index++, "_SC_VersionTweak", prVersionTweak, 1, 0);
4269 
4270     // void initOscilPrimitives();
4271     // void initControllerPrimitives();
4272 
4273     // initOscilPrimitives();
4274     // initControllerPrimitives();
4275     initMathPrimitives();
4276     initSignalPrimitives();
4277     initArrayPrimitives();
4278     initAudioDevicePrimitives();
4279 
4280     void initSymbolPrimitives();
4281     initSymbolPrimitives();
4282 
4283     void initArchiverPrimitives();
4284     initArchiverPrimitives();
4285 
4286     void initArrayPrimitives();
4287     initArrayPrimitives();
4288 
4289     void initBitPrimitives();
4290     initBitPrimitives();
4291 
4292     void initCharPrimitives();
4293     initCharPrimitives();
4294 
4295     void initFilePrimitives();
4296     initFilePrimitives();
4297 
4298     void initPlatformPrimitives();
4299     initPlatformPrimitives();
4300 
4301     void initStringPrimitives();
4302     initStringPrimitives();
4303 
4304     void initListPrimitives();
4305     initListPrimitives();
4306 
4307     void initUnixPrimitives();
4308     initUnixPrimitives();
4309 
4310     void init_OSC_primitives();
4311     init_OSC_primitives();
4312 
4313     void initGUIPrimitives();
4314     initGUIPrimitives();
4315 
4316 #ifdef SC_APP
4317     void initSCViewPrimitives();
4318     initSCViewPrimitives();
4319 
4320     void initRendezvousPrimitives();
4321     initRendezvousPrimitives();
4322 
4323     void initCocoaFilePrimitives();
4324     initCocoaFilePrimitives();
4325 #endif
4326 
4327     void initSchedPrimitives();
4328     initSchedPrimitives();
4329 
4330 #ifdef SC_ABLETON_LINK
4331     void initLinkPrimitives();
4332     initLinkPrimitives();
4333 #endif
4334 
4335 #ifdef SC_HIDAPI
4336     void initHIDAPIPrimitives();
4337     initHIDAPIPrimitives();
4338 #endif
4339 
4340 #if defined(__APPLE__) || defined(HAVE_ALSA) || defined(HAVE_PORTMIDI)
4341     void initMIDIPrimitives();
4342     initMIDIPrimitives();
4343 #endif
4344 
4345 #if defined __linux__
4346     void initLIDPrimitives();
4347     initLIDPrimitives();
4348 #endif
4349 
4350     void initSerialPrimitives();
4351     initSerialPrimitives();
4352 
4353 #ifdef SCOGL_COMPILE
4354     void initOpenGLPrimitives();
4355     initOpenGLPrimitives();
4356 #endif
4357 
4358 #ifdef SC_QT
4359     QtCollider::initPrimitives();
4360 #endif
4361 
4362 #ifdef SC_IDE
4363     void initScIDEPrimitives();
4364     initScIDEPrimitives();
4365 #endif
4366 
4367     initSCDocPrimitives();
4368 
4369     s_recvmsg = getsym("receiveMsg");
4370     post("\tFound %d primitives.\n", nextPrimitiveIndex());
4371 }
4372 
deinitPrimitives()4373 void deinitPrimitives() {
4374 #ifdef SC_HIDAPI
4375     void deinitHIDAPIPrimitives();
4376     deinitHIDAPIPrimitives();
4377 #endif
4378 #if defined(HAVE_PORTMIDI) || defined(HAVE_ALSA)
4379     void deinitMIDIPrimitives();
4380     deinitMIDIPrimitives();
4381 #endif
4382 }
4383 
4384 
4385 void initThreads();
initThreads()4386 void initThreads() {
4387     s_prrunnextthread = getsym("prRunNextThread");
4388     s_prready = getsym("prReady");
4389 }
4390