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