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 <atomic>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <limits.h>
26 #include "GC.h"
27 #include "PyrMessage.h"
28 #include "PyrInterpreter.h"
29 #include "PyrSymbolTable.h"
30 #include "PyrObjectProto.h"
31 #include "PyrKernelProto.h"
32 #include "PyrLexer.h"
33 #include "InitAlloc.h"
34 #include "Hash.h"
35 #include "SC_Constants.h"
36 #include "SC_Alloca.h"
37 #include "SC_Lock.h"
38 
39 #include <set>
40 #include <limits>
41 
42 #include <memory>
43 #include <boost/range/irange.hpp>
44 
45 #define BOOST_THREAD_VERSION 4
46 #define BOOST_THREAD_PROVIDES_EXECUTORS
47 
48 #include <boost/thread/future.hpp>
49 #include <boost/thread/executor.hpp>
50 #include <boost/thread/executors/basic_thread_pool.hpp>
51 
52 #ifdef _MSC_VER
53 #    include <future>
54 #endif
55 
56 #if 0 // not yet
57 #    include <parallel/algorithm>
58 #endif
59 
60 
61 PyrClass* gClassList = nullptr;
62 int gNumSelectors = 0;
63 int gNumClasses = 0;
64 int gNumClassVars = 0;
65 int gFormatElemSize[NUMOBJFORMATS];
66 int gFormatElemCapc[NUMOBJFORMATS];
67 int gFormatElemTag[NUMOBJFORMATS];
68 PyrMethod* gNullMethod; // used to fill row table
69 PyrClass* gTagClassTable[16];
70 
71 PyrClass* class_object;
72 PyrClass* class_dict;
73 PyrClass* class_array;
74 PyrClass *class_list, *class_method, *class_fundef, *class_frame, *class_class;
75 PyrClass *class_symbol, *class_nil;
76 PyrClass *class_boolean, *class_true, *class_false;
77 PyrClass *class_int, *class_char, *class_float, *class_complex;
78 PyrClass* class_rawptr;
79 PyrClass* class_string;
80 PyrClass *class_magnitude, *class_number, *class_collection, *class_ordered_collection;
81 PyrClass* class_arrayed_collection;
82 PyrClass* class_sequenceable_collection;
83 PyrClass* class_simple_number;
84 PyrClass* class_rawarray;
85 PyrClass* class_signal;
86 PyrClass* class_wavetable;
87 PyrClass* class_floatarray;
88 PyrClass* class_int8array;
89 PyrClass* class_int16array;
90 PyrClass* class_int32array;
91 PyrClass* class_symbolarray;
92 PyrClass* class_doublearray;
93 PyrClass *class_func, *class_absfunc;
94 PyrClass* class_stream;
95 PyrClass* class_process;
96 PyrClass* class_interpreter;
97 PyrClass* class_thread;
98 PyrClass* class_routine;
99 PyrClass* class_finalizer;
100 PyrClass* class_server_shm_interface;
101 
102 PyrSymbol* s_none;
103 PyrSymbol* s_object;
104 PyrSymbol* s_bag;
105 PyrSymbol* s_set;
106 PyrSymbol* s_identityset;
107 PyrSymbol* s_dictionary;
108 PyrSymbol* s_identitydictionary;
109 PyrSymbol* s_linkedlist;
110 PyrSymbol* s_sortedlist;
111 PyrSymbol* s_array;
112 PyrSymbol *s_list, *s_method, *s_fundef, *s_frame, *s_class;
113 PyrSymbol *s_symbol, *s_nil;
114 PyrSymbol *s_boolean, *s_true, *s_false;
115 PyrSymbol *s_int, *s_char, *s_color, *s_float, *s_complex;
116 PyrSymbol* s_rawptr;
117 PyrSymbol* s_string;
118 PyrSymbol *s_magnitude, *s_number, *s_collection, *s_ordered_collection;
119 PyrSymbol* s_arrayed_collection;
120 PyrSymbol* s_sequenceable_collection;
121 PyrSymbol* s_simple_number;
122 PyrSymbol* s_signal;
123 PyrSymbol* s_wavetable;
124 
125 PyrSymbol* s_rawarray;
126 PyrSymbol* s_int8array;
127 PyrSymbol* s_int16array;
128 PyrSymbol* s_int32array;
129 PyrSymbol* s_symbolarray;
130 PyrSymbol* s_doublearray;
131 PyrSymbol* s_floatarray;
132 PyrSymbol* s_rect;
133 PyrSymbol *s_func, *s_absfunc;
134 PyrSymbol* s_stream;
135 PyrSymbol* s_process;
136 PyrSymbol* s_main;
137 PyrSymbol* s_thread;
138 PyrSymbol* s_routine;
139 PyrSymbol* s_task;
140 PyrSymbol* s_prstart;
141 PyrSymbol* s_interpreter;
142 PyrSymbol* s_finalizer;
143 PyrSymbol* s_awake;
144 PyrSymbol* s_systemclock;
145 PyrSymbol* s_server_shm_interface;
146 PyrSymbol *s_interpretCmdLine, *s_interpretPrintCmdLine;
147 
148 PyrSymbol* s_doesNotUnderstand;
149 PyrSymbol *s_curProcess, *s_curMethod, *s_curBlock, *s_curClosure, *s_curThread;
150 PyrSymbol *s_run, *s_stop, *s_tick;
151 PyrSymbol* s_startup;
152 PyrSymbol* s_next;
153 PyrSymbol* s_env;
154 PyrSymbol *s_new, *s_ref, *s_value, *s_at, *s_put;
155 PyrSymbol *s_performList, *s_superPerformList;
156 PyrSymbol *s_series, *s_copyseries, *s_putseries;
157 PyrSymbol *s_envirGet, *s_envirPut;
158 PyrSymbol *s_synth, *s_environment, *s_event;
159 PyrSymbol* s_shutdown;
160 PyrSymbol *s_super, *s_this;
161 
162 PyrSlot o_nil, o_true, o_false;
163 PyrSlot o_fhalf, o_fnegone, o_fzero, o_fone, o_ftwo, o_inf;
164 PyrSlot o_negone, o_zero, o_one, o_two;
165 PyrSlot o_none;
166 PyrSlot o_emptyarray, o_onenilarray, o_argnamethis;
167 
168 
initSymbols()169 void initSymbols() {
170     // basic keywords
171     s_new = getsym("new");
172     s_none = getsym("__none");
173     /* Dummy symbol for null superclass or primitive. Prefixed with
174      * `__` to avoid collisions with possible method and primitive names.
175      */
176     s_this = getsym("this");
177     s_super = getsym("super");
178     s_curProcess = getsym("thisProcess");
179     s_curThread = getsym("thisThread");
180     s_curMethod = getsym("thisMethod");
181     s_curBlock = getsym("thisFunctionDef");
182     s_curClosure = getsym("thisFunction");
183 
184     // classes
185     s_object = getsym("Object");
186     s_ref = getsym("Ref");
187     s_dictionary = getsym("Dictionary");
188     s_bag = getsym("Bag");
189     s_set = getsym("Set");
190     s_identityset = getsym("IdentitySet");
191     s_identitydictionary = getsym("IdentityDictionary");
192     s_linkedlist = getsym("LinkedList");
193     s_sortedlist = getsym("SortedList");
194     s_array = getsym("Array");
195     s_list = getsym("List");
196     s_method = getsym("Method");
197     s_fundef = getsym("FunctionDef");
198     s_frame = getsym("Frame");
199     s_class = getsym("Class");
200     s_symbol = getsym("Symbol");
201     s_nil = getsym("Nil");
202     s_true = getsym("True");
203     s_false = getsym("False");
204     s_int = getsym("Integer");
205     s_float = getsym("Float");
206     s_char = getsym("Char");
207     s_color = getsym("Color");
208     s_rawptr = getsym("RawPointer");
209     s_string = getsym("String");
210     s_magnitude = getsym("Magnitude");
211     s_number = getsym("Number");
212     s_simple_number = getsym("SimpleNumber");
213     s_collection = getsym("Collection");
214     s_arrayed_collection = getsym("ArrayedCollection");
215     s_sequenceable_collection = getsym("SequenceableCollection");
216     s_boolean = getsym("Boolean");
217     s_signal = getsym("Signal");
218     s_wavetable = getsym("Wavetable");
219     s_rawarray = getsym("RawArray");
220     s_int8array = getsym("Int8Array");
221     s_int16array = getsym("Int16Array");
222     s_int32array = getsym("Int32Array");
223     s_symbolarray = getsym("SymbolArray");
224     s_floatarray = getsym("FloatArray");
225     s_doublearray = getsym("DoubleArray");
226     s_complex = getsym("Complex");
227     s_rect = getsym("Rect");
228     s_absfunc = getsym("AbstractFunction");
229     s_func = getsym("Function");
230     s_stream = getsym("Stream");
231     s_process = getsym("Process");
232     s_main = getsym("Main");
233     s_thread = getsym("Thread");
234     s_routine = getsym("Routine");
235     s_task = getsym("Task");
236     s_interpreter = getsym("Interpreter");
237     s_finalizer = getsym("Finalizer");
238     s_systemclock = getsym("SystemClock");
239     s_server_shm_interface = getsym("ServerShmInterface");
240     s_env = getsym("Env");
241     s_synth = getsym("Synth");
242     s_environment = getsym("Environment");
243     s_event = getsym("Event");
244 
245     // interpreter
246     s_interpretCmdLine = getsym("interpretCmdLine");
247     s_interpretPrintCmdLine = getsym("interpretPrintCmdLine");
248 
249     s_doesNotUnderstand = getsym("doesNotUnderstand");
250 
251     s_startup = getsym("startup");
252     s_awake = getsym("awake");
253     s_shutdown = getsym("shutdown");
254 
255     // methods
256     s_run = getsym("run");
257     s_stop = getsym("stop");
258     s_tick = getsym("tick");
259     s_next = getsym("next");
260     s_value = getsym("value");
261     s_performList = getsym("performList");
262     s_superPerformList = getsym("superPerformList");
263     s_at = getsym("at");
264     s_put = getsym("put");
265     s_prstart = getsym("prStart");
266     s_series = getsym("prSimpleNumberSeries");
267     s_copyseries = getsym("copySeries");
268     s_putseries = getsym("putSeries");
269 
270     s_envirGet = getsym("envirGet");
271     s_envirPut = getsym("envirPut");
272 
273     // set special value slots
274     SetSymbol(&o_none, s_none);
275 
276     SetNil(&o_nil);
277     SetFalse(&o_false);
278     SetTrue(&o_true);
279 
280     SetInt(&o_negone, -1);
281     SetInt(&o_zero, 0);
282     SetInt(&o_one, 1);
283     SetInt(&o_two, 2);
284 
285     SetFloat(&o_fhalf, .5);
286     SetFloat(&o_fnegone, -1.);
287     SetFloat(&o_fzero, 0.);
288     SetFloat(&o_fone, 1.);
289     SetFloat(&o_ftwo, 2.);
290     SetFloat(&o_inf, std::numeric_limits<double>::infinity());
291 
292     slotCopy(&gSpecialValues[svNil], &o_nil);
293     slotCopy(&gSpecialValues[svFalse], &o_false);
294     slotCopy(&gSpecialValues[svTrue], &o_true);
295 
296     slotCopy(&gSpecialValues[svNegOne], &o_negone);
297     slotCopy(&gSpecialValues[svZero], &o_zero);
298     slotCopy(&gSpecialValues[svOne], &o_one);
299     slotCopy(&gSpecialValues[svTwo], &o_two);
300 
301     slotCopy(&gSpecialValues[svFHalf], &o_fhalf);
302     slotCopy(&gSpecialValues[svFNegOne], &o_fnegone);
303     slotCopy(&gSpecialValues[svFZero], &o_fzero);
304     slotCopy(&gSpecialValues[svFOne], &o_fone);
305     slotCopy(&gSpecialValues[svFTwo], &o_ftwo);
306     slotCopy(&gSpecialValues[svInf], &o_inf);
307 
308 
309     gFormatElemSize[obj_notindexed] = sizeof(PyrSlot);
310     gFormatElemSize[obj_slot] = sizeof(PyrSlot);
311     gFormatElemSize[obj_double] = sizeof(double);
312     gFormatElemSize[obj_float] = sizeof(float);
313     gFormatElemSize[obj_int32] = sizeof(int32);
314     gFormatElemSize[obj_int16] = sizeof(int16);
315     gFormatElemSize[obj_int8] = sizeof(int8);
316     gFormatElemSize[obj_char] = sizeof(char);
317     gFormatElemSize[obj_symbol] = sizeof(PyrSymbol*);
318 
319     gFormatElemCapc[obj_notindexed] = sizeof(PyrSlot) / sizeof(PyrSlot);
320     gFormatElemCapc[obj_slot] = sizeof(PyrSlot) / sizeof(PyrSlot);
321     gFormatElemCapc[obj_double] = sizeof(PyrSlot) / sizeof(double);
322     gFormatElemCapc[obj_float] = sizeof(PyrSlot) / sizeof(float);
323     gFormatElemCapc[obj_int32] = sizeof(PyrSlot) / sizeof(int32);
324     gFormatElemCapc[obj_int16] = sizeof(PyrSlot) / sizeof(int16);
325     gFormatElemCapc[obj_int8] = sizeof(PyrSlot) / sizeof(int8);
326     gFormatElemCapc[obj_char] = sizeof(PyrSlot) / sizeof(char);
327     gFormatElemCapc[obj_symbol] = sizeof(PyrSlot) / sizeof(PyrSymbol*);
328 
329     gFormatElemTag[obj_notindexed] = -1;
330     gFormatElemTag[obj_slot] = -1;
331     gFormatElemTag[obj_double] = 0;
332     gFormatElemTag[obj_float] = 0;
333     gFormatElemTag[obj_int32] = tagInt;
334     gFormatElemTag[obj_int16] = tagInt;
335     gFormatElemTag[obj_int8] = tagInt;
336     gFormatElemTag[obj_char] = tagChar;
337     gFormatElemTag[obj_symbol] = tagSym;
338 }
339 
slotSymString(PyrSlot * slot)340 const char* slotSymString(PyrSlot* slot) {
341     switch (GetTag(slot)) {
342     case tagObj:
343         return slotRawSymbol(&slotRawObject(slot)->classptr->name)->name;
344     case tagInt:
345         return "Integer";
346     case tagChar:
347         return "Char";
348     case tagSym:
349         return slotRawSymbol(slot)->name;
350     case tagNil:
351         return "Nil";
352     case tagFalse:
353         return "False";
354     case tagTrue:
355         return "True";
356     default:
357         return "<float>";
358     }
359 }
360 
newClassObj(PyrClass * classObjSuperClass,PyrSymbol * className,PyrSymbol * superClassName,int numInstVars,int numClassVars,int numConsts,int numInstMethods,int instFormat,int instFlags)361 PyrClass* newClassObj(PyrClass* classObjSuperClass, PyrSymbol* className, PyrSymbol* superClassName, int numInstVars,
362                       int numClassVars, int numConsts, int numInstMethods, int instFormat, int instFlags) {
363     PyrClass *classobj, *superclassobj;
364     PyrObject* array;
365     PyrSymbolArray* symarray;
366     int classFlags;
367 
368     /*{
369         int c;
370         c = className->name[0];
371         if (!(c >= 'A' && c <= 'Z')) Debugger();
372     }*/
373     // pyrmalloc:
374     // lifetime: kill upon recompiling library
375     classobj = (PyrClass*)pyr_pool_runtime->Alloc(sizeof(PyrClass));
376     MEMFAIL(classobj);
377     classobj->size = (sizeof(PyrClass) - sizeof(PyrObjectHdr)) / sizeof(PyrSlot);
378     classobj->prev = classobj->next = nullptr;
379     classobj->obj_flags = obj_immutable;
380     classobj->obj_format = obj_notindexed;
381     classobj->gc_color = obj_permanent;
382     classobj->obj_sizeclass = LOG2CEIL(classobj->size);
383     classobj->classptr = classObjSuperClass;
384 
385 
386     // append to the list of classes
387     if (gClassList)
388         SetObject(&classobj->nextclass, gClassList);
389     else
390         SetNil(&classobj->nextclass);
391 
392     gClassList = classobj;
393 
394     className->u.classobj = classobj;
395     // postfl("> '%s' %d %d\n", className->name, className, classobj);
396 
397     SetSymbol(&classobj->name, className);
398     if (superClassName) {
399         SetSymbol(&classobj->superclass, superClassName);
400         superclassobj = superClassName->u.classobj;
401     } else {
402         SetSymbol(&classobj->superclass, s_none);
403         superclassobj = nullptr;
404     }
405 
406     SetInt(&classobj->subclasses, 0); // to be filled with subclasses later
407     // in the meantime it is used as a tally of subclasses so that its allocation
408     // size can be known
409 
410     if (numInstMethods) {
411         array = newPyrArray(nullptr, numInstMethods, obj_permanent | obj_immutable, false);
412         SetObject(&classobj->methods, array);
413     } else {
414         SetNil(&classobj->methods);
415     }
416 
417     if (numInstVars) {
418         symarray = newPyrSymbolArray(nullptr, numInstVars, obj_permanent | obj_immutable, false);
419         SetObject(&classobj->instVarNames, symarray);
420 
421         array = newPyrArray(nullptr, numInstVars, obj_permanent | obj_immutable, false);
422         SetObject(&classobj->iprototype, array);
423         nilSlots(array->slots, numInstVars);
424     } else {
425         SetNil(&classobj->instVarNames);
426         SetNil(&classobj->iprototype);
427     }
428 
429     if (numClassVars) {
430         symarray = newPyrSymbolArray(nullptr, numClassVars, obj_permanent | obj_immutable, false);
431         SetObject(&classobj->classVarNames, symarray);
432 
433         array = newPyrArray(nullptr, numClassVars, obj_permanent | obj_immutable, false);
434         SetObject(&classobj->cprototype, array);
435         nilSlots(array->slots, numClassVars);
436     } else {
437         SetNil(&classobj->classVarNames);
438         SetNil(&classobj->cprototype);
439     }
440 
441     if (numConsts) {
442         symarray = newPyrSymbolArray(nullptr, numConsts, obj_permanent | obj_immutable, false);
443         SetObject(&classobj->constNames, symarray);
444 
445         array = newPyrArray(nullptr, numConsts, obj_permanent | obj_immutable, false);
446         SetObject(&classobj->constValues, array);
447         nilSlots(array->slots, numConsts);
448     } else {
449         SetNil(&classobj->constNames);
450         SetNil(&classobj->constValues);
451     }
452 
453     classFlags = 0;
454     if (instFormat != obj_notindexed) {
455         classFlags |= classHasIndexableInstances;
456     }
457 
458     SetInt(&classobj->instanceFormat, instFormat);
459     SetInt(&classobj->instanceFlags, instFlags);
460     SetInt(&classobj->classIndex, -1);
461     SetInt(&classobj->classFlags, classFlags);
462     SetInt(&classobj->maxSubclassIndex, 0);
463     SetNil(&classobj->filenameSym);
464     SetInt(&classobj->charPos, 0);
465     SetInt(&classobj->classVarIndex, gNumClassVars);
466     // if (numClassVars) post("%16s %4d %4d\n", className->name, gNumClassVars, numClassVars);
467     gNumClassVars += numClassVars;
468     return classobj;
469 }
470 
reallocClassObj(PyrClass * classobj,int numInstVars,int numClassVars,int numConsts,int numMethods,int instFormat,int instFlags)471 void reallocClassObj(PyrClass* classobj, int numInstVars, int numClassVars, int numConsts, int numMethods,
472                      int instFormat, int instFlags) {
473     PyrObject* array;
474     PyrSymbolArray* symarray;
475     PyrClass* superclassobj;
476 
477     freePyrSlot(&classobj->methods);
478     freePyrSlot(&classobj->instVarNames);
479     freePyrSlot(&classobj->classVarNames);
480     freePyrSlot(&classobj->iprototype);
481     freePyrSlot(&classobj->cprototype);
482 
483     freePyrSlot(&classobj->constNames);
484     freePyrSlot(&classobj->constValues);
485 
486     if (numMethods) {
487         array = newPyrArray(nullptr, numMethods, obj_permanent | obj_immutable, false);
488         SetObject(&classobj->methods, array);
489     } else {
490         SetNil(&classobj->methods);
491     }
492 
493     if (numInstVars) {
494         // post("reallocClassObj %s numInstVars %d\n", slotRawSymbol(&classobj->name)->name, numInstVars);
495         symarray = newPyrSymbolArray(nullptr, numInstVars, obj_permanent | obj_immutable, false);
496         SetObject(&classobj->instVarNames, symarray);
497 
498         array = newPyrArray(nullptr, numInstVars, obj_permanent | obj_immutable, false);
499         SetObject(&classobj->iprototype, array);
500         nilSlots(array->slots, numInstVars);
501     } else {
502         SetNil(&classobj->instVarNames);
503         SetNil(&classobj->iprototype);
504     }
505 
506     if (numClassVars) {
507         // post("reallocClassObj %s numClassVars %d\n", slotRawSymbol(&classobj->name)->name, numClassVars);
508         symarray = newPyrSymbolArray(nullptr, numClassVars, obj_permanent | obj_immutable, false);
509         SetObject(&classobj->classVarNames, symarray);
510         nilSlots(array->slots, numClassVars);
511 
512         array = newPyrArray(nullptr, numClassVars, obj_permanent | obj_immutable, false);
513         SetObject(&classobj->cprototype, array);
514         nilSlots(array->slots, numClassVars);
515     } else {
516         SetNil(&classobj->classVarNames);
517         SetNil(&classobj->cprototype);
518     }
519 
520     if (numConsts) {
521         // post("reallocClassObj %s numConsts %d\n", slotRawSymbol(&classobj->name)->name, numConsts);
522         symarray = newPyrSymbolArray(nullptr, numConsts, obj_permanent | obj_immutable, false);
523         SetObject(&classobj->constNames, symarray);
524 
525         array = newPyrArray(nullptr, numConsts, obj_permanent | obj_immutable, false);
526         SetObject(&classobj->constValues, array);
527         nilSlots(array->slots, numConsts);
528     } else {
529         SetNil(&classobj->constNames);
530         SetNil(&classobj->constValues);
531     }
532 
533     superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj;
534 
535     SetInt(&classobj->instanceFormat, instFormat);
536     SetInt(&classobj->instanceFlags, instFlags);
537     SetInt(&classobj->classIndex, -1);
538 }
539 
540 void fixClassArrays(PyrClass* classobj);
fixClassArrays(PyrClass * classobj)541 void fixClassArrays(PyrClass* classobj) {
542     if (IsObj(&classobj->methods))
543         slotRawObject(&classobj->methods)->classptr = class_array;
544     if (IsObj(&classobj->instVarNames))
545         slotRawObject(&classobj->instVarNames)->classptr = class_symbolarray;
546     if (IsObj(&classobj->classVarNames))
547         slotRawObject(&classobj->classVarNames)->classptr = class_symbolarray;
548     if (IsObj(&classobj->iprototype))
549         slotRawObject(&classobj->iprototype)->classptr = class_array;
550     if (IsObj(&classobj->cprototype))
551         slotRawObject(&classobj->cprototype)->classptr = class_array;
552 }
553 
numInstVars(PyrClass * classobj)554 int numInstVars(PyrClass* classobj) {
555     int res;
556     if (IsNil(&classobj->instVarNames))
557         res = 0;
558     else
559         res = slotRawObject(&classobj->instVarNames)->size;
560     return res;
561 }
562 
numClassVars(PyrClass * classobj)563 int numClassVars(PyrClass* classobj) {
564     int res;
565     if (IsNil(&classobj->classVarNames))
566         res = 0;
567     else
568         res = slotRawObject(&classobj->classVarNames)->size;
569     return res;
570 }
571 
572 
573 void objAddIndexedSlotGrow(PyrSlot* arraySlot, PyrSlot* addSlot);
objAddIndexedSlotGrow(PyrSlot * arraySlot,PyrSlot * addSlot)574 void objAddIndexedSlotGrow(PyrSlot* arraySlot, PyrSlot* addSlot) {
575     PyrObject* obj;
576     if (IsNil(arraySlot)) {
577         PyrObject* newobj = (PyrObject*)newPyrArray(nullptr, 1, obj_permanent | obj_immutable, false);
578         SetObject(arraySlot, newobj);
579         obj = newobj;
580     } else {
581         obj = slotRawObject(arraySlot);
582         if (obj->size >= ARRAYMAXINDEXSIZE(obj)) {
583             // post("objAddIndexedSlotGrow\n");
584             PyrObject* newobj = (PyrObject*)newPyrArray(nullptr, obj->size * 2, obj_permanent | obj_immutable, false);
585             memcpy(newobj->slots, obj->slots, obj->size * sizeof(PyrSlot));
586             newobj->size = obj->size;
587             SetObject(arraySlot, newobj);
588             pyr_pool_runtime->Free((void*)obj);
589             obj = newobj;
590         }
591     }
592     slotCopy(&obj->slots[obj->size++], addSlot);
593 }
594 
addMethod(PyrClass * classobj,PyrMethod * method)595 void addMethod(PyrClass* classobj, PyrMethod* method) {
596     PyrSlot slot;
597     SetObject(&slot, method);
598     objAddIndexedSlotGrow(&classobj->methods, &slot);
599 }
600 
601 
classFindDirectMethod(PyrClass * classobj,PyrSymbol * name)602 PyrMethod* classFindDirectMethod(PyrClass* classobj, PyrSymbol* name) {
603     PyrMethod* method;
604     PyrSlot* methods;
605     int i, numMethods;
606     if (IsNil(&classobj->methods))
607         return nullptr;
608     methods = slotRawObject(&classobj->methods)->slots;
609     numMethods = slotRawObject(&classobj->methods)->size;
610     for (i = 0; i < numMethods; ++i) {
611         method = slotRawMethod(&methods[i]);
612         if (slotRawSymbol(&method->name) == name)
613             break;
614     }
615     if (i >= numMethods)
616         method = nullptr;
617     return method;
618 }
619 
numSuperInstVars(PyrClass * superclassobj)620 int numSuperInstVars(PyrClass* superclassobj) {
621     int superinstvars = 0;
622     if (superclassobj) {
623         if (IsObj(&superclassobj->iprototype)) {
624             superinstvars = slotRawObject(&superclassobj->iprototype)->size;
625         }
626     }
627     return superinstvars;
628 }
629 
classFindInstVar(PyrClass * classobj,PyrSymbol * name,int * index)630 bool classFindInstVar(PyrClass* classobj, PyrSymbol* name, int* index) {
631     PyrSymbolArray* ivnames;
632     PyrSymbol* ivname;
633     int i;
634     if (NotNil(&classobj->instVarNames)) {
635         ivnames = slotRawSymbolArray(&classobj->instVarNames);
636         if (ivnames) {
637             for (i = 0; i < ivnames->size; ++i) {
638                 ivname = ivnames->symbols[i];
639                 if (ivname == name) {
640                     // numsupervars = numSuperInstVars(slotRawSymbol(&classobj->superclass)->u.classobj);
641                     //*index = numsupervars + i;
642                     *index = i;
643                     return true;
644                 }
645             }
646         }
647     }
648     return false;
649 }
650 
instVarOffset(const char * classname,const char * instvarname)651 int instVarOffset(const char* classname, const char* instvarname) {
652     PyrSymbol *instvarsymbol, *classsymbol;
653     PyrClass* classobj;
654     int index;
655     char c;
656 
657     classsymbol = getsym(classname);
658     instvarsymbol = getsym(instvarname);
659 
660     c = classname[0];
661     if (!(c >= 'A' && c <= 'Z'))
662         return -1;
663 
664     classobj = classsymbol->u.classobj;
665     if (!classobj)
666         return -1;
667     if (!classFindInstVar(classobj, instvarsymbol, &index))
668         return -1;
669     return index;
670 }
671 
classVarOffset(const char * classname,const char * classvarname,PyrClass ** classobj)672 int classVarOffset(const char* classname, const char* classvarname, PyrClass** classobj) {
673     PyrSymbol *classvarsymbol, *classsymbol;
674     int index;
675     char c;
676 
677     classsymbol = getsym(classname);
678     classvarsymbol = getsym(classvarname);
679 
680     c = classname[0];
681     if (!(c >= 'A' && c <= 'Z'))
682         return -1;
683 
684     *classobj = classsymbol->u.classobj;
685     if (!*classobj)
686         return -1;
687     if (!classFindClassVar(classobj, classvarsymbol, &index))
688         return -1;
689     return index;
690 }
691 
classFindClassVar(PyrClass ** classobj,PyrSymbol * name,int * index)692 bool classFindClassVar(PyrClass** classobj, PyrSymbol* name, int* index) {
693     PyrSymbolArray* cvnames;
694     PyrSymbol* cvname;
695     int i, j;
696     char* classname;
697     PyrClass* localclassobj = *classobj;
698     // if this is a Metaclass then we need to search its normal Class for
699     // the class vars
700     classname = slotRawSymbol(&localclassobj->name)->name;
701     if (strncmp(classname, "Meta_", 5) == 0) {
702         localclassobj = getsym(classname + 5)->u.classobj;
703     }
704     for (j = 0; localclassobj; ++j) {
705         if (NotNil(&localclassobj->classVarNames)) {
706             cvnames = slotRawSymbolArray(&localclassobj->classVarNames);
707             if (cvnames) {
708                 for (i = 0; i < cvnames->size; ++i) {
709                     cvname = cvnames->symbols[i];
710                     if (cvname == name) {
711                         *classobj = localclassobj;
712                         *index = i;
713                         return true;
714                     }
715                 }
716             }
717         }
718         if (IsSym(&localclassobj->superclass)) {
719             localclassobj = slotRawSymbol(&localclassobj->superclass)->u.classobj;
720         } else {
721             localclassobj = nullptr;
722         }
723     }
724     return false;
725 }
726 
classFindConst(PyrClass ** classobj,PyrSymbol * name,int * index)727 bool classFindConst(PyrClass** classobj, PyrSymbol* name, int* index) {
728     PyrSymbolArray* knames;
729     PyrSymbol* kname;
730     int i, j;
731     char* classname;
732     PyrClass* localclassobj = *classobj;
733     // if this is a Metaclass then we need to search its normal Class for
734     // the class vars
735     classname = slotRawSymbol(&localclassobj->name)->name;
736     if (strncmp(classname, "Meta_", 5) == 0) {
737         localclassobj = getsym(classname + 5)->u.classobj;
738     }
739     for (j = 0; localclassobj; ++j) {
740         if (NotNil(&localclassobj->constNames)) {
741             knames = slotRawSymbolArray(&localclassobj->constNames);
742             if (knames) {
743                 for (i = 0; i < knames->size; ++i) {
744                     kname = knames->symbols[i];
745                     if (kname == name) {
746                         *classobj = localclassobj;
747                         *index = i;
748                         return true;
749                     }
750                 }
751             }
752         }
753         if (IsSym(&localclassobj->superclass)) {
754             localclassobj = slotRawSymbol(&localclassobj->superclass)->u.classobj;
755         } else {
756             localclassobj = nullptr;
757         }
758     }
759     return false;
760 }
761 
762 struct compareByName {
operator ()compareByName763     bool operator()(PyrClass* lhs, PyrClass* rhs) const {
764         return strcmp(slotRawSymbol(&lhs->name)->name, slotRawSymbol(&rhs->name)->name) < 0;
765     }
766 };
767 
768 
769 template <class T> class pyr_pool_compile_allocator {
770 public:
771     typedef std::size_t size_type;
772     typedef std::ptrdiff_t difference_type;
773     typedef T* pointer;
774     typedef const T* const_pointer;
775     typedef T& reference;
776     typedef const T& const_reference;
777     typedef T value_type;
778 
779     template <class U> struct rebind { typedef pyr_pool_compile_allocator<U> other; };
780 
pyr_pool_compile_allocator(void)781     pyr_pool_compile_allocator(void) {}
782 
pyr_pool_compile_allocator(pyr_pool_compile_allocator<U> const &)783     template <class U> pyr_pool_compile_allocator(pyr_pool_compile_allocator<U> const&) {}
784 
address(reference x) const785     pointer address(reference x) const { return &x; }
786 
address(const_reference x) const787     const_pointer address(const_reference x) const { return &x; }
788 
allocate(size_type n,const void * hint=nullptr)789     pointer allocate(size_type n, const void* hint = nullptr) {
790         return (pointer)pyr_pool_compile->Alloc(n * sizeof(T));
791     }
792 
deallocate(pointer p,size_type n)793     void deallocate(pointer p, size_type n) { pyr_pool_compile->Free(p); }
794 
construct(pointer p,const T & val)795     void construct(pointer p, const T& val) { ::new (p) T(val); }
796 
destroy(pointer p)797     void destroy(pointer p) { p->~T(); }
798 };
799 
800 
801 /* sort list of classes:
802  * we fill a binary search tree
803  *
804  */
sortClasses(PyrClass * aClassList)805 static PyrClass* sortClasses(PyrClass* aClassList) {
806     typedef std::set<PyrClass*, compareByName, pyr_pool_compile_allocator<PyrClass*>> classSetType;
807     classSetType classSet;
808 
809     PyrClass* insertHead = aClassList;
810     do {
811         assert(classSet.find(insertHead) == classSet.end());
812         classSet.insert(insertHead);
813         insertHead = slotRawClass(&insertHead->nextclass);
814     } while (insertHead);
815 
816     classSetType::iterator it = classSet.begin();
817     PyrClass* sortedClasses = *it;
818     ++it;
819 
820     PyrClass* lastClass = sortedClasses;
821     for (; it != classSet.end(); ++it) {
822         PyrClass* current = *it;
823         SetObject(&lastClass->nextclass, (PyrObject*)current);
824         lastClass = current;
825     }
826     SetNil(&lastClass->nextclass);
827     return sortedClasses;
828 }
829 
830 
buildClassTree()831 void buildClassTree() {
832     // after all classes are compiled this function builds the tree and
833     // indexes the classes
834 
835     // count subclasses
836     // postfl("count subclasses\n");
837     PyrClass* classobj = gClassList;
838     while (classobj) {
839         PyrClass* superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj;
840         if (superclassobj) {
841             // postfl("     superclassobj %s\n", slotRawSymbol(&superclassobj->name)->name);
842             SetRaw(&superclassobj->subclasses, slotRawInt(&superclassobj->subclasses) + 1);
843         }
844         classobj = slotRawClass(&classobj->nextclass);
845     }
846     // allocate subclass arrays
847     // postfl("allocate subclass arrays\n");
848     classobj = gClassList;
849     while (classobj) {
850         int numSubclasses;
851         numSubclasses = slotRawInt(&classobj->subclasses);
852         // postfl("  %s %d\n", slotRawSymbol(&classobj->name)->name, numSubclasses);
853         if (numSubclasses) {
854             SetObject(&classobj->subclasses,
855                       (PyrObject*)newPyrArray(nullptr, numSubclasses, obj_permanent | obj_immutable, false));
856             slotRawObject(&classobj->subclasses)->size = 0;
857         } else {
858             SetNil(&classobj->subclasses);
859         }
860         classobj = slotRawClass(&classobj->nextclass);
861     }
862     // fill in subclass arrays
863     // postfl("fill in subclass arrays\n");
864     classobj = gClassList;
865     while (classobj) {
866         // postfl("  %s\n", slotRawSymbol(&classobj->name)->name);
867         PyrClass* superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj;
868         if (superclassobj) {
869             objAddIndexedObject(slotRawObject(&superclassobj->subclasses), (PyrObject*)classobj);
870             // postfl("     superclassobj %s %d\n", slotRawSymbol(&superclassobj->name)->name,
871             //	slotRawObject(&superclassobj->subclasses)->size);
872         }
873         classobj = slotRawClass(&classobj->nextclass);
874     }
875 
876     // alpha sort the classes via insertion sort
877     gClassList = sortClasses(gClassList);
878 }
879 
indexClassTree(PyrClass * classobj,int numSuperMethods)880 void indexClassTree(PyrClass* classobj, int numSuperMethods) {
881     int i, numMethods;
882 
883     if (!classobj)
884         return;
885 
886     SetInt(&classobj->classIndex, gNumClasses);
887     gNumClasses++;
888 
889     if (IsObj(&classobj->methods)) {
890         PyrObject* methods = slotRawObject(&classobj->methods);
891         numMethods = methods->size;
892     } else
893         numMethods = 0;
894 
895     numMethods = numSuperMethods + numMethods;
896     if (IsObj(&classobj->subclasses)) {
897         PyrObject* subclasses = slotRawObject(&classobj->subclasses);
898         for (i = 0; i < subclasses->size; ++i)
899             indexClassTree(slotRawClass(&subclasses->slots[i]), numMethods);
900     }
901     SetInt(&classobj->maxSubclassIndex, gNumClasses - 1);
902 }
903 
904 void findDiscrepancy();
findDiscrepancy()905 void findDiscrepancy() {
906     PyrClass *classobjA, *classobjB;
907 
908     classobjA = gClassList;
909     while (classobjA) {
910         classobjB = slotRawClass(&classobjA->nextclass);
911         ;
912         while (classobjB) {
913             if (slotRawSymbol(&classobjA->name) == slotRawSymbol(&classobjB->name)) {
914                 post("duplicate %s\n", slotRawSymbol(&classobjA->name)->name);
915             }
916             classobjB = slotRawClass(&classobjB->nextclass);
917         }
918         classobjA = slotRawClass(&classobjA->nextclass);
919     }
920 }
921 
922 
indent(int n)923 static void indent(int n) {
924     for (int i = 0; i < n; ++i) {
925         post("  ");
926     }
927 }
928 
postClassTree(PyrClass * classobj,int level)929 void postClassTree(PyrClass* classobj, int level) {
930     PyrObject* subclasses;
931     int i;
932 
933     // post("%4d  ", slotRawInt(&classobj->classIndex));
934     indent(level);
935     post("%s\n", slotRawSymbol(&classobj->name)->name);
936 
937     if (classobj == class_class) {
938         indent(level + 1);
939         post("      [.. all metaclasses ..]\n");
940     } else {
941         if (IsNil(&classobj->subclasses))
942             return; // FIXME: can we initialize subclasses with a NULL pointer?
943         subclasses = slotRawObject(&classobj->subclasses);
944         if (subclasses) {
945             // determine if can put on one line
946             bool oneline = subclasses->size <= 5;
947             for (i = 0; oneline && i < subclasses->size; ++i) {
948                 PyrClass* subclassobj = slotRawClass(&subclasses->slots[i]);
949                 if (IsObj(&subclassobj->subclasses))
950                     // FIXME: shall we do a null-pointer check?
951                     oneline = false;
952             }
953             if (oneline) {
954                 indent(level + 1);
955                 post("[");
956                 for (i = 0; i < subclasses->size; ++i) {
957                     PyrClass* subclassobj = slotRawClass(&subclasses->slots[i]);
958                     post(" %s", slotRawSymbol(&subclassobj->name)->name);
959                 }
960                 post(" ]\n");
961             } else {
962                 indent(level);
963                 post("[\n");
964                 for (i = 0; i < subclasses->size; ++i) {
965                     postClassTree(slotRawClass(&subclasses->slots[i]), level + 1);
966                 }
967                 indent(level);
968                 post("]\n");
969             }
970         }
971     }
972 }
973 
974 
setSelectorFlags()975 void setSelectorFlags() {
976     int i;
977 
978     PyrClass* classobj = gClassList;
979     while (classobj) {
980         if (IsObj(&classobj->methods)) {
981             PyrObject* methods = slotRawObject(&classobj->methods);
982             for (i = 0; i < methods->size; ++i) {
983                 PyrMethod* method = slotRawMethod(&methods->slots[i]);
984                 slotRawSymbol(&method->name)->flags |= sym_Selector;
985                 // if (method->methType == methRedirect) {
986                 //	post("rd: %3d %s:%s\n", k++, slotRawSymbol(&classobj->name)->name,
987                 //		slotRawSymbol(&method->name)->name);
988                 //}
989             }
990         }
991         classobj = slotRawClass(&classobj->nextclass);
992     }
993     // count selectors
994     gNumSelectors = 0;
995     SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
996     for (int i = 0; i < symbolTable->TableSize(); ++i) {
997         PyrSymbol* sym = symbolTable->Get(i);
998         if (sym && (sym->flags & sym_Selector)) {
999             sym->u.index = gNumSelectors++;
1000         }
1001     }
1002     // post("gNumSelectors %d\n", gNumSelectors);
1003 }
1004 
1005 // the chunky stuff can be commented back in for implementing a better
1006 // compression scheme. The Q&D method works fine for my small class tree for now.
1007 
1008 typedef struct {
1009     PyrSymbol* selector;
1010     int minClassIndex;
1011     int maxClassIndex;
1012     int rowWidth;
1013     // int largestChunk;
1014     // int chunkOffset;
1015     int selectorIndex;
1016     int population;
1017     int rowOffset;
1018 } ColumnDescriptor;
1019 
1020 int compareColDescs(const void* va, const void* vb);
compareColDescs(const void * va,const void * vb)1021 int compareColDescs(const void* va, const void* vb) {
1022     ColumnDescriptor* a = (ColumnDescriptor*)va;
1023     ColumnDescriptor* b = (ColumnDescriptor*)vb;
1024     int diff;
1025     // diff = b->largestChunk - a->largestChunk;
1026     // if (diff != 0) return diff;
1027     diff = b->rowWidth - a->rowWidth;
1028     if (diff != 0)
1029         return diff;
1030     // diff = b->chunkOffset - a->chunkOffset;
1031     diff = b->minClassIndex - a->minClassIndex;
1032     return diff;
1033 }
1034 
1035 #define CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME 0
1036 #if CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME
1037 double elapsedTime();
1038 #endif
1039 
1040 #ifdef _MSC_VER
1041 static size_t fillClassRows(const PyrClass* classobj, PyrMethod** bigTable);
1042 #else
1043 static size_t fillClassRows(const PyrClass* classobj, PyrMethod** bigTable, boost::basic_thread_pool& pool);
1044 #endif
1045 
1046 
binsortClassRows(PyrMethod const ** bigTable,const ColumnDescriptor * sels,size_t numSelectors,size_t begin,size_t end)1047 static void binsortClassRows(PyrMethod const** bigTable, const ColumnDescriptor* sels, size_t numSelectors,
1048                              size_t begin, size_t end) {
1049     // bin sort the class rows to the new ordering
1050     // post("reorder rows\n");
1051     const int allocaThreshold = 16384;
1052     PyrMethod** temprow = (numSelectors < allocaThreshold) ? (PyrMethod**)alloca(numSelectors * sizeof(PyrMethod*))
1053                                                            : (PyrMethod**)malloc(numSelectors * sizeof(PyrMethod*));
1054 
1055     for (int j = begin; j < end; ++j) {
1056         PyrMethod const** row = bigTable + j * numSelectors;
1057         memcpy(temprow, row, numSelectors * sizeof(PyrMethod*));
1058 
1059 #pragma GCC ivdep
1060         for (int i = 0; i < numSelectors; ++i)
1061             row[i] = temprow[sels[i].selectorIndex];
1062     }
1063 
1064     if (numSelectors >= allocaThreshold)
1065         free(temprow);
1066 }
1067 
prepareColumnTable(ColumnDescriptor * sels,int numSelectors)1068 static ColumnDescriptor* prepareColumnTable(ColumnDescriptor* sels, int numSelectors) {
1069     // fill selector table
1070     // post("fill selector table\n");
1071     SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1072 
1073     int selectorTableIndex = 0;
1074     for (int i : boost::irange(0, symbolTable->TableSize())) {
1075         PyrSymbol* sym = symbolTable->Get(i);
1076         if (sym && (sym->flags & sym_Selector))
1077             sels[selectorTableIndex++].selector = sym;
1078     }
1079     assert(selectorTableIndex == numSelectors);
1080 
1081     for (int i = 0; i < numSelectors; ++i) {
1082         // postfl("%3d %s\n", i, sels[i].selector->name);
1083         sels[i].minClassIndex = INT_MAX;
1084         sels[i].maxClassIndex = 0;
1085         // sels[i].largestChunk = 0;
1086         // sels[i].chunkOffset = 0;
1087         sels[i].selectorIndex = i;
1088         sels[i].population = 0;
1089     }
1090     return sels;
1091 }
1092 
1093 
calcRowStats(PyrMethod const * const * bigTable,ColumnDescriptor * sels,int numClasses,int numSelectors,int begin,int end)1094 static void calcRowStats(PyrMethod const* const* bigTable, ColumnDescriptor* sels, int numClasses, int numSelectors,
1095                          int begin, int end) {
1096     // chunkSize = 0;
1097     // chunkOffset = 0;
1098     for (int classIndex = 0; classIndex < numClasses; ++classIndex) {
1099         for (int selectorIndex = begin; selectorIndex < end; ++selectorIndex) {
1100             PyrMethod const* method = bigTable[classIndex * numSelectors + selectorIndex];
1101             if (method) {
1102                 // classobj = method->ownerclass.uoc;
1103                 if (classIndex > sels[selectorIndex].maxClassIndex)
1104                     sels[selectorIndex].maxClassIndex = classIndex;
1105 
1106                 if (classIndex < sels[selectorIndex].minClassIndex)
1107                     sels[selectorIndex].minClassIndex = classIndex;
1108 
1109                 sels[selectorIndex].population++;
1110                 // if (chunkSize == 0) chunkOffset = j;
1111                 // chunkSize++;
1112                 // postfl("    %8s %3d %3d %3d %3d\n", slotRawSymbol(&classobj->name)->name, i, j,
1113                 //	chunkSize, slotRawInt(&classobj->classIndex));
1114                 //} else {
1115                 // if (chunkSize > sels[i].largestChunk) {
1116                 //	sels[i].largestChunk = chunkSize;
1117                 //	sels[i].chunkOffset = chunkOffset;
1118                 //}
1119                 // chunkSize = 0;
1120             }
1121         }
1122     }
1123 
1124     for (int i = begin; i < end; ++i)
1125         sels[i].rowWidth = sels[i].maxClassIndex - sels[i].minClassIndex + 1;
1126 }
1127 
buildBigMethodMatrix()1128 void buildBigMethodMatrix() {
1129     PyrMethod **bigTable, **row;
1130     PyrClass** classes;
1131     int j, k;
1132     int popSum, widthSum;
1133     int rowOffset, freeIndex;
1134     int rowTableSize;
1135     int bigTableSize;
1136     const size_t numSelectors = gNumSelectors;
1137     const size_t numClasses = gNumClasses;
1138     // post("allocate arrays\n");
1139 
1140 #if CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME
1141     double t0 = elapsedTime();
1142 #endif
1143 
1144     const int hw_concurrency = SC_Thread::hardware_concurrency();
1145     const int cpuCount = hw_concurrency > 0 ? hw_concurrency : 1;
1146     const int helperThreadCount = cpuCount > 1 ? cpuCount - 1 : 1;
1147     boost::basic_thread_pool pool(helperThreadCount);
1148 
1149     // pyrmalloc:
1150     // lifetime: kill after compile
1151     bigTableSize = numSelectors * numClasses;
1152     // post("bigTableSize %d %d %d\n", bigTableSize, numSelectors, numClasses);
1153     ColumnDescriptor* sels = (ColumnDescriptor*)pyr_pool_compile->Alloc(numSelectors * sizeof(ColumnDescriptor));
1154     MEMFAIL(sels);
1155 #ifdef _MSC_VER
1156     auto filledSelectorsFuture = std::async(std::launch::deferred, std::bind(&prepareColumnTable, sels, numSelectors));
1157 #else
1158     auto filledSelectorsFuture = boost::async(pool, std::bind(&prepareColumnTable, sels, numSelectors));
1159 #endif
1160 
1161     classes = (PyrClass**)pyr_pool_compile->Alloc(numClasses * sizeof(PyrClass*));
1162     MEMFAIL(classes);
1163 
1164     auto fillClassIndices = [](PyrClass** classes) {
1165         PyrClass* classobj = gClassList;
1166         while (classobj) {
1167             classes[slotRawInt(&classobj->classIndex)] = classobj;
1168             classobj = slotRawClass(&classobj->nextclass);
1169         }
1170         return classes;
1171     };
1172 #ifdef _MSC_VER
1173     auto filledClassIndices = std::async(std::launch::deferred, fillClassIndices, classes);
1174 #else
1175     auto filledClassIndices = boost::async(pool, fillClassIndices, classes);
1176 #endif
1177 
1178     bigTable = (PyrMethod**)pyr_pool_compile->Alloc(bigTableSize * sizeof(PyrMethod*));
1179     MEMFAIL(bigTable);
1180 
1181 #ifndef _MSC_VER
1182     pool.try_executing_one();
1183 #endif
1184     filledClassIndices.wait();
1185 #ifdef _MSC_VER
1186     size_t numentries = fillClassRows(class_object, bigTable);
1187 #else
1188     size_t numentries = fillClassRows(class_object, bigTable, pool);
1189 #endif
1190     post("\tnumentries = %lu / %d = %.2g\n", numentries, bigTableSize, (double)numentries / (double)bigTableSize);
1191 
1192 
1193     ColumnDescriptor* filledSelectors = filledSelectorsFuture.get();
1194 #ifdef _MSC_VER
1195     std::vector<std::future<void>> columnDescriptorsWithStats;
1196 #else
1197     std::vector<boost::future<void>> columnDescriptorsWithStats;
1198 #endif
1199     size_t selectorsPerJob = numSelectors / cpuCount / 2;
1200     for (size_t beginSelectorIndex : boost::irange(selectorsPerJob, numSelectors, selectorsPerJob)) {
1201         size_t endSelectorIndex = std::min(beginSelectorIndex + selectorsPerJob, numSelectors);
1202 #ifdef _MSC_VER
1203         auto future = std::async(std::launch::deferred, calcRowStats, bigTable, filledSelectors, numClasses,
1204                                  numSelectors, beginSelectorIndex, endSelectorIndex);
1205 #else
1206         auto future = boost::async(pool, calcRowStats, bigTable, filledSelectors, numClasses, numSelectors,
1207                                    beginSelectorIndex, endSelectorIndex);
1208 #endif
1209         columnDescriptorsWithStats.push_back(std::move(future));
1210     }
1211 
1212     calcRowStats(bigTable, filledSelectors, numClasses, numSelectors, 0, std::min(selectorsPerJob, numSelectors));
1213 
1214     for (auto& future : columnDescriptorsWithStats) {
1215 #ifdef _MSC_VER
1216         future.wait();
1217 #else
1218         while (!future.is_ready())
1219             pool.schedule_one_or_yield();
1220 #endif
1221     }
1222 
1223     // post("qsort\n");
1224     // sort rows by largest chunk, then by width, then by chunk offset
1225 
1226 #if 0 // not yet
1227 	__gnu_parallel::sort(sels, sels + numSelectors, [](ColumnDescriptor const & rhs, ColumnDescriptor const & lhs) {
1228 		return compareColDescs(&rhs, &lhs) < 0;
1229 	});
1230 #else
1231     std::sort(sels, sels + numSelectors,
1232               [](ColumnDescriptor const& rhs, ColumnDescriptor const& lhs) { return compareColDescs(&rhs, &lhs) < 0; });
1233 #endif
1234 
1235     // bin sort the class rows to the new ordering
1236     // post("reorder rows\n");
1237 #ifdef _MSC_VER
1238     std::vector<std::future<void>> binsortedClassRowFuture;
1239 #else
1240     std::vector<boost::future<void>> binsortedClassRowFuture;
1241 #endif
1242     size_t classesPerJob = numClasses / cpuCount / 2;
1243     for (size_t beginClassIndex : boost::irange(classesPerJob, numClasses, classesPerJob)) {
1244         size_t endClassIndex = std::min(beginClassIndex + classesPerJob, numClasses);
1245 #ifdef _MSC_VER
1246         auto future = std::async(std::launch::deferred, binsortClassRows, (PyrMethod const**)bigTable, sels,
1247                                  numSelectors, beginClassIndex, endClassIndex);
1248 #else
1249         auto future = boost::async(pool, binsortClassRows, (PyrMethod const**)bigTable, sels, numSelectors,
1250                                    beginClassIndex, endClassIndex);
1251 #endif
1252         binsortedClassRowFuture.push_back(std::move(future));
1253     }
1254 
1255     binsortClassRows((PyrMethod const**)bigTable, sels, numSelectors, 0, std::min(classesPerJob, numClasses));
1256 
1257     for (auto& future : binsortedClassRowFuture) {
1258 #ifdef _MSC_VER
1259         future.wait();
1260 #else
1261         while (!future.is_ready())
1262             pool.schedule_one_or_yield();
1263 #endif
1264     }
1265 
1266     // post("calc row offsets %d\n", numSelectors);
1267     widthSum = 0;
1268     popSum = 0;
1269     freeIndex = 0;
1270     rowOffset = -1;
1271     for (int i = 0; i < numSelectors; ++i) {
1272         widthSum += sels[i].rowWidth;
1273         popSum += sels[i].population;
1274         rowOffset = sc_max(rowOffset + 1, freeIndex - sels[i].minClassIndex);
1275         freeIndex = rowOffset + sels[i].maxClassIndex + 1;
1276         sels[i].rowOffset = rowOffset;
1277         sels[i].selector->u.index = rowOffset;
1278         // post("%3d  %24s %3d %5d %5d\n", i, sels[i].selector->name,
1279         //	sels[i].rowWidth, rowOffset, freeIndex);
1280     }
1281     // post("alloc row table %d\n", freeIndex);
1282     rowTableSize = (freeIndex + numClasses) * sizeof(PyrMethod*);
1283     gRowTable = (PyrMethod**)pyr_pool_runtime->Alloc(rowTableSize);
1284     MEMFAIL(gRowTable);
1285 
1286     // having the method ptr always be valid saves a branch in SendMessage()
1287     for (int i = 0; i < freeIndex + numClasses; ++i)
1288         gRowTable[i] = gNullMethod;
1289 
1290     // post("fill compressed table\n");
1291     //{ FILE* fp;
1292     // newPyrMethod
1293     // fp = fopen("meth table", "w");
1294     for (int i = 0; i < numSelectors; ++i) {
1295         int offset, maxwidth;
1296         offset = sels[i].rowOffset + sels[i].minClassIndex;
1297         maxwidth = offset + sels[i].rowWidth;
1298         row = bigTable + sels[i].minClassIndex * numSelectors + i;
1299         PyrMethod** table = gRowTable;
1300         for (j = offset, k = 0; j < maxwidth; ++j, k += numSelectors) {
1301             if (row[k])
1302                 table[j] = row[k];
1303         }
1304     }
1305     // fclose(fp);
1306     //}
1307 
1308     for (int i = 0; i < freeIndex + numClasses; ++i)
1309         assert(gRowTable[i]);
1310 
1311 
1312         // post("freeIndex %d\n", freeIndex);
1313         // post("widthSum %d\n", widthSum);
1314         // post("popSum %d\n", popSum);
1315 
1316 #if CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME
1317     post("building table took %.3g seconds\n", elapsedTime() - t0);
1318     {
1319         int numFilled = 0;
1320         for (int i = 0; i < rowTableSize / sizeof(PyrMethod*); ++i) {
1321             if (gRowTable[i] != gNullMethod)
1322                 numFilled++;
1323         }
1324         post("Filled %d of %d = %f percent\n", numFilled, rowTableSize / sizeof(PyrMethod*),
1325              100. * (double)numFilled / (rowTableSize / sizeof(PyrMethod*)));
1326     }
1327 #endif
1328     post("\t%d method selectors, %d classes\n", numSelectors, numClasses);
1329     post("\tmethod table size %d bytes, ", rowTableSize);
1330     post("big table size %d\n", numSelectors * numClasses * sizeof(PyrMethod*));
1331     // postfl("%p %p %p\n", classes, bigTable, sels);
1332     /*
1333         // not necessary since the entire pool will be freed..
1334         pyr_pool_compile->Free(classes);
1335         pyr_pool_compile->Free(bigTable);
1336         pyr_pool_compile->Free(sels);
1337     */
1338 }
1339 
1340 #ifdef _MSC_VER
fillClassRow(const PyrClass * classobj,PyrMethod ** bigTable)1341 static size_t fillClassRow(const PyrClass* classobj, PyrMethod** bigTable)
1342 #else
1343 static size_t fillClassRow(const PyrClass* classobj, PyrMethod** bigTable, boost::basic_thread_pool& pool)
1344 #endif
1345 {
1346     size_t count = 0;
1347 
1348     PyrMethod** myrow = bigTable + slotRawInt(&classobj->classIndex) * gNumSelectors;
1349     PyrClass* superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj;
1350     if (superclassobj) {
1351         PyrMethod** superrow = bigTable + slotRawInt(&superclassobj->classIndex) * gNumSelectors;
1352 
1353 #pragma GCC ivdep
1354         for (int i = 0; i != gNumSelectors; ++i) {
1355             myrow[i] = superrow[i];
1356             if (superrow[i])
1357                 ++count;
1358         }
1359 
1360     } else {
1361         memset(myrow, 0, gNumSelectors * sizeof(PyrMethod*));
1362     }
1363 
1364     if (IsObj(&classobj->methods)) {
1365         PyrObject* methods = const_cast<PyrObject*>(slotRawObject(&classobj->methods));
1366         // postfl("        %d\n", methods->size);
1367         for (int i = 0; i < methods->size; ++i) {
1368             PyrMethod* method = slotRawMethod(&methods->slots[i]);
1369             int selectorIndex = slotRawSymbol(&method->name)->u.index;
1370 
1371             if (myrow[selectorIndex] == nullptr)
1372                 ++count;
1373 
1374             myrow[selectorIndex] = method;
1375         }
1376     }
1377 
1378     size_t result = count;
1379 
1380     if (IsObj(&classobj->subclasses)) {
1381         const PyrObject* subclasses = slotRawObject(&classobj->subclasses);
1382         int numSubclasses = subclasses->size;
1383 
1384         if (numSubclasses) {
1385 #ifdef _MSC_VER
1386             if (numSubclasses <= 2) {
1387                 for (int subClassIndex : boost::irange(0, numSubclasses))
1388                     result += fillClassRow(slotRawClass(&subclasses->slots[subClassIndex]), bigTable);
1389             } else {
1390                 typedef std::vector<std::future<size_t>> VectorOfFutures;
1391 
1392                 VectorOfFutures subclassResults;
1393                 for (int subClassIndex : boost::irange(1, numSubclasses)) {
1394                     auto subclassResult = std::async(std::launch::deferred, fillClassRow,
1395                                                      slotRawClass(&subclasses->slots[subClassIndex]), bigTable);
1396                     subclassResults.emplace_back(std::move(subclassResult));
1397                 }
1398 
1399                 result += fillClassRow(slotRawClass(&subclasses->slots[0]), bigTable);
1400 
1401                 for (auto& subclassResult : subclassResults) {
1402                     result += subclassResult.get();
1403                 }
1404             }
1405 #else
1406             if (numSubclasses <= 2) {
1407                 for (int subClassIndex : boost::irange(0, numSubclasses))
1408                     result += fillClassRow(slotRawClass(&subclasses->slots[subClassIndex]), bigTable, pool);
1409             } else {
1410                 typedef std::vector<boost::future<size_t>> VectorOfFutures;
1411 
1412                 VectorOfFutures subclassResults;
1413                 for (int subClassIndex : boost::irange(1, numSubclasses)) {
1414                     auto subclassResult =
1415                         boost::async(pool, fillClassRow, slotRawClass(&subclasses->slots[subClassIndex]), bigTable,
1416                                      boost::ref(pool));
1417                     subclassResults.emplace_back(std::move(subclassResult));
1418                 }
1419 
1420                 result += fillClassRow(slotRawClass(&subclasses->slots[0]), bigTable, pool);
1421 
1422                 for (auto& subclassResult : subclassResults) {
1423                     while (!subclassResult.is_ready())
1424                         pool.schedule_one_or_yield();
1425 
1426                     result += subclassResult.get();
1427                 }
1428             }
1429 #endif
1430         }
1431     }
1432 
1433     return result;
1434 }
1435 
1436 #ifdef _MSC_VER
fillClassRows(const PyrClass * classobj,PyrMethod ** bigTable)1437 static size_t fillClassRows(const PyrClass* classobj, PyrMethod** bigTable) { return fillClassRow(classobj, bigTable); }
1438 #else
fillClassRows(const PyrClass * classobj,PyrMethod ** bigTable,boost::basic_thread_pool & pool)1439 static size_t fillClassRows(const PyrClass* classobj, PyrMethod** bigTable, boost::basic_thread_pool& pool) {
1440     return fillClassRow(classobj, bigTable, pool);
1441 }
1442 #endif
1443 
funcFindArg(PyrBlock * func,PyrSymbol * name,int * index)1444 bool funcFindArg(PyrBlock* func, PyrSymbol* name, int* index) {
1445     int i;
1446     for (i = 0; i < slotRawSymbolArray(&func->argNames)->size; ++i) {
1447         if (slotRawSymbolArray(&func->argNames)->symbols[i] == name) {
1448             *index = i;
1449             return true;
1450         }
1451     }
1452     return false;
1453 }
1454 
funcFindVar(PyrBlock * func,PyrSymbol * name,int * index)1455 bool funcFindVar(PyrBlock* func, PyrSymbol* name, int* index) {
1456     int i;
1457     for (i = 0; i < slotRawSymbolArray(&func->varNames)->size; ++i) {
1458         if (slotRawSymbolArray(&func->varNames)->symbols[i] == name) {
1459             *index = i;
1460             return true;
1461         }
1462     }
1463     return false;
1464 }
1465 
makeIntrinsicClass(PyrSymbol * className,PyrSymbol * superClassName,int numInstVars,int numClassVars)1466 PyrClass* makeIntrinsicClass(PyrSymbol* className, PyrSymbol* superClassName, int numInstVars, int numClassVars) {
1467     PyrClass* superClass = nullptr;
1468     PyrClass* metaSuperClass = nullptr;
1469     PyrSymbol* metaClassName = nullptr;
1470     PyrSymbol* metaSuperClassName = nullptr;
1471     PyrClass* classobj = nullptr;
1472     PyrClass* metaclassobj = nullptr;
1473     int superInstVars;
1474 
1475     // postfl("makeIntrinsicClass '%s'\n", className->name);
1476     if (superClassName) {
1477         superClass = superClassName->u.classobj;
1478         if (!superClass) {
1479             error("Can't find superclass '%s' of '%s'\n", superClassName->name, className->name);
1480             return nullptr;
1481         }
1482         metaSuperClassName = getmetasym(superClassName->name);
1483         metaSuperClass = metaSuperClassName->u.classobj;
1484         superInstVars = numSuperInstVars(superClass);
1485     } else {
1486         // else it must be Object and so has no superclass
1487         metaSuperClassName = nullptr;
1488         superInstVars = 0;
1489     }
1490 
1491     metaClassName = getmetasym(className->name);
1492     metaClassName->flags |= sym_MetaClass;
1493     metaclassobj =
1494         newClassObj(class_class, metaClassName, metaSuperClassName, classClassNumInstVars, 0, 0, 0, obj_notindexed, 0);
1495     SetInt(&metaclassobj->classFlags, slotRawInt(&metaclassobj->classFlags) | classIsIntrinsic);
1496 
1497     if (metaSuperClassName && classClassNumInstVars) {
1498         memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&metaSuperClass->iprototype)->slots,
1499                sizeof(PyrSlot) * classClassNumInstVars);
1500         memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols,
1501                slotRawSymbolArray(&metaSuperClass->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars);
1502         slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars;
1503         slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars;
1504         // dumpObject((PyrObject*)metaclassobj);
1505     }
1506 
1507     classobj = newClassObj(metaclassobj, className, superClassName, numInstVars + superInstVars, numClassVars, 0, 0,
1508                            obj_notindexed, 0);
1509     SetInt(&classobj->classFlags, slotRawInt(&classobj->classFlags) | classIsIntrinsic);
1510 
1511     // postfl("%s:%s  : %d\n", className->name, superClassName->name, superInstVars);
1512     if (superClass && superInstVars) {
1513         memcpy(slotRawObject(&classobj->iprototype)->slots, slotRawObject(&superClass->iprototype)->slots,
1514                sizeof(PyrSlot) * superInstVars);
1515         memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols,
1516                slotRawSymbolArray(&superClass->instVarNames)->symbols, sizeof(PyrSymbol*) * superInstVars);
1517         slotRawObject(&classobj->iprototype)->size = superInstVars;
1518         slotRawObject(&classobj->instVarNames)->size = superInstVars;
1519     }
1520 
1521     return classobj;
1522 }
1523 
addIntrinsicVar(PyrClass * classobj,const char * varName,PyrSlot * slot)1524 void addIntrinsicVar(PyrClass* classobj, const char* varName, PyrSlot* slot) {
1525     // postfl("%s  %s  %d\n", slotRawSymbol(&classobj->name)->name, varName,
1526     //	slotRawObject(&classobj->instVarNames)->size);
1527     objAddIndexedSymbol(slotRawSymbolArray(&classobj->instVarNames), getsym(varName));
1528     objAddIndexedSlot(slotRawObject(&classobj->iprototype), slot);
1529 }
1530 
1531 void addIntrinsicClassVar(PyrClass* classobj, const char* varName, PyrSlot* slot);
addIntrinsicClassVar(PyrClass * classobj,const char * varName,PyrSlot * slot)1532 void addIntrinsicClassVar(PyrClass* classobj, const char* varName, PyrSlot* slot) {
1533     // postfl("%s  %s  %d\n", slotRawSymbol(&classobj->name)->name, varName,
1534     //	slotRawObject(&classobj->instVarNames)->size);
1535     objAddIndexedSymbol(slotRawSymbolArray(&classobj->classVarNames), getsym(varName));
1536     objAddIndexedSlot(slotRawObject(&classobj->cprototype), slot);
1537 }
1538 
initClasses()1539 void initClasses() {
1540     PyrClass* class_object_meta;
1541     PyrMethodRaw* methraw;
1542 
1543     // BOOTSTRAP THE OBJECT HIERARCHY
1544 
1545     gNumClassVars = 0;
1546     gClassList = nullptr;
1547     gNullMethod = newPyrMethod();
1548     SetSymbol(&gNullMethod->name, (PyrSymbol*)nullptr);
1549     methraw = METHRAW(gNullMethod);
1550     methraw->methType = methNormal;
1551 
1552     // build intrinsic classes
1553     class_class = nullptr;
1554     class_object = makeIntrinsicClass(s_object, nullptr, 0, 4);
1555     class_class = makeIntrinsicClass(s_class, s_object, classClassNumInstVars, 1);
1556 
1557     // now fix class_class ptrs that were just previously installed erroneously
1558     class_object->classptr->classptr = class_class;
1559     class_class->classptr->classptr = class_class;
1560     class_object_meta = class_object->classptr;
1561     class_object_meta->superclass = class_class->name;
1562 
1563     addIntrinsicClassVar(class_object, "dependantsDictionary", &o_nil);
1564     addIntrinsicClassVar(class_object, "currentEnvironment", &o_nil);
1565     addIntrinsicClassVar(class_object, "topEnvironment", &o_nil);
1566     addIntrinsicClassVar(class_object, "uniqueMethods", &o_nil);
1567 
1568     // declare varNames for Class
1569 
1570     addIntrinsicVar(class_class, "name", &o_nil);
1571     addIntrinsicVar(class_class, "nextclass", &o_nil);
1572     addIntrinsicVar(class_class, "superclass", &o_nil);
1573     addIntrinsicVar(class_class, "subclasses", &o_nil);
1574     addIntrinsicVar(class_class, "methods", &o_nil);
1575 
1576     addIntrinsicVar(class_class, "instVarNames", &o_nil);
1577     addIntrinsicVar(class_class, "classVarNames", &o_nil);
1578     addIntrinsicVar(class_class, "iprototype", &o_nil);
1579     addIntrinsicVar(class_class, "cprototype", &o_nil);
1580 
1581     addIntrinsicVar(class_class, "constNames", &o_nil);
1582     addIntrinsicVar(class_class, "constValues", &o_nil);
1583 
1584     addIntrinsicVar(class_class, "instanceFormat", &o_nil);
1585     addIntrinsicVar(class_class, "instanceFlags", &o_zero);
1586     addIntrinsicVar(class_class, "classIndex", &o_zero);
1587     addIntrinsicVar(class_class, "classFlags", &o_zero);
1588     addIntrinsicVar(class_class, "maxSubclassIndex", &o_zero);
1589     addIntrinsicVar(class_class, "filenameSymbol", &o_nil);
1590     addIntrinsicVar(class_class, "charPos", &o_zero);
1591     addIntrinsicVar(class_class, "classVarIndex", &o_zero);
1592 
1593     addIntrinsicClassVar(class_class, "classesInited", &o_nil);
1594 
1595     // class_object_meta's inst var names need to be copied from class_class
1596     // because class_class didn't exist when it was created
1597     memcpy(slotRawObject(&class_object_meta->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots,
1598            sizeof(PyrSlot) * classClassNumInstVars);
1599     memcpy(slotRawSymbolArray(&class_object_meta->instVarNames)->symbols,
1600            slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars);
1601 
1602     memcpy(slotRawObject(&class_class->classptr->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots,
1603            sizeof(PyrSlot) * classClassNumInstVars);
1604     memcpy(slotRawSymbolArray(&class_class->classptr->instVarNames)->symbols,
1605            slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars);
1606 
1607 
1608     // OK the next thing I need is arrays..
1609     class_collection = makeIntrinsicClass(s_collection, s_object, 0, 0);
1610     class_sequenceable_collection = makeIntrinsicClass(s_sequenceable_collection, s_collection, 0, 0);
1611 
1612     class_arrayed_collection = makeIntrinsicClass(s_arrayed_collection, s_sequenceable_collection, 0, 0);
1613     class_array = makeIntrinsicClass(s_array, s_arrayed_collection, 0, 0);
1614     SetInt(&class_array->instanceFormat, obj_slot);
1615     SetInt(&class_array->classFlags, slotRawInt(&class_array->classFlags) | classHasIndexableInstances);
1616 
1617     // now fix array classptrs in already created classes
1618     fixClassArrays(class_class);
1619     fixClassArrays(class_class->classptr);
1620     fixClassArrays(class_object_meta);
1621     fixClassArrays(class_collection);
1622     fixClassArrays(class_sequenceable_collection);
1623     fixClassArrays(class_arrayed_collection);
1624     fixClassArrays(class_array);
1625 
1626     class_fundef = makeIntrinsicClass(s_fundef, s_object, 10, 0);
1627     // declare varNames for Block
1628 
1629     addIntrinsicVar(class_fundef, "raw1", &o_nil);
1630     addIntrinsicVar(class_fundef, "raw2", &o_nil);
1631     addIntrinsicVar(class_fundef, "code", &o_nil);
1632     addIntrinsicVar(class_fundef, "selectors", &o_nil);
1633     addIntrinsicVar(class_fundef, "constants", &o_nil);
1634 
1635     addIntrinsicVar(class_fundef, "prototypeFrame", &o_nil);
1636     addIntrinsicVar(class_fundef, "context", &o_nil);
1637     addIntrinsicVar(class_fundef, "argNames", &o_nil);
1638     addIntrinsicVar(class_fundef, "varNames", &o_nil);
1639     addIntrinsicVar(class_fundef, "sourceCode", &o_nil);
1640 
1641     class_method = makeIntrinsicClass(s_method, s_fundef, 5, 0);
1642     addIntrinsicVar(class_method, "ownerClass", &o_nil);
1643     addIntrinsicVar(class_method, "name", &o_nil);
1644     addIntrinsicVar(class_method, "primitiveName", &o_nil);
1645     addIntrinsicVar(class_method, "filenameSymbol", &o_nil);
1646     addIntrinsicVar(class_method, "charPos", &o_zero);
1647     // addIntrinsicVar(class_method, "byteMeter", &o_zero);
1648     // addIntrinsicVar(class_method, "callMeter", &o_zero);
1649 
1650     class_frame = makeIntrinsicClass(s_frame, s_object, 0, 0);
1651     SetInt(&class_frame->classFlags, slotRawInt(&class_frame->classFlags) | classHasIndexableInstances);
1652     // addIntrinsicVar(class_frame, "method", &o_nil);
1653     // addIntrinsicVar(class_frame, "caller", &o_nil);
1654     // addIntrinsicVar(class_frame, "context", &o_nil);
1655     // addIntrinsicVar(class_frame, "homeContext", &o_nil);
1656     // addIntrinsicVar(class_frame, "ip", &o_nil);
1657 
1658     class_process = makeIntrinsicClass(s_process, s_object, 6, 0);
1659     addIntrinsicVar(class_process, "classVars", &o_nil);
1660     addIntrinsicVar(class_process, "interpreter", &o_nil);
1661     addIntrinsicVar(class_process, "curThread", &o_nil);
1662     addIntrinsicVar(class_process, "mainThread", &o_nil);
1663     addIntrinsicVar(class_process, "schedulerQueue", &o_nil);
1664     addIntrinsicVar(class_process, "nowExecutingPath", &o_nil);
1665 
1666     class_interpreter = makeIntrinsicClass(s_interpreter, s_object, 29, 0);
1667     addIntrinsicVar(class_interpreter, "cmdLine", &o_nil);
1668     addIntrinsicVar(class_interpreter, "context", &o_nil);
1669     for (int i = 0; i < 26; ++i) {
1670         char name[2];
1671         name[0] = 'a' + i;
1672         name[1] = 0;
1673         addIntrinsicVar(class_interpreter, name, &o_nil);
1674     }
1675     addIntrinsicVar(class_interpreter, "codeDump", &o_nil);
1676     addIntrinsicVar(class_interpreter, "preProcessor", &o_nil);
1677 
1678     class_absfunc = makeIntrinsicClass(s_absfunc, s_object, 0, 0);
1679     class_stream = makeIntrinsicClass(s_stream, s_absfunc, 0, 0);
1680 
1681     class_thread = makeIntrinsicClass(s_thread, s_stream, 27, 0);
1682     addIntrinsicVar(class_thread, "state", &o_nil);
1683     addIntrinsicVar(class_thread, "func", &o_nil);
1684     addIntrinsicVar(class_thread, "stack", &o_nil);
1685     addIntrinsicVar(class_thread, "method", &o_nil);
1686     addIntrinsicVar(class_thread, "block", &o_nil);
1687     addIntrinsicVar(class_thread, "frame", &o_nil);
1688     addIntrinsicVar(class_thread, "ip", &o_zero);
1689     addIntrinsicVar(class_thread, "sp", &o_zero);
1690     addIntrinsicVar(class_thread, "numpop", &o_zero);
1691     addIntrinsicVar(class_thread, "receiver", &o_nil);
1692     addIntrinsicVar(class_thread, "numArgsPushed", &o_zero);
1693     addIntrinsicVar(class_thread, "parent", &o_nil);
1694     addIntrinsicVar(class_thread, "terminalValue", &o_nil);
1695 
1696     addIntrinsicVar(class_thread, "primitiveError", &o_zero);
1697     addIntrinsicVar(class_thread, "primitiveIndex", &o_zero);
1698     addIntrinsicVar(class_thread, "randData", &o_zero);
1699     addIntrinsicVar(class_thread, "beats", &o_fzero);
1700     addIntrinsicVar(class_thread, "seconds", &o_fzero);
1701     addIntrinsicVar(class_thread, "clock", &o_nil);
1702     addIntrinsicVar(class_thread, "nextBeat", &o_nil);
1703     addIntrinsicVar(class_thread, "endBeat", &o_nil);
1704     addIntrinsicVar(class_thread, "endValue", &o_nil);
1705 
1706     addIntrinsicVar(class_thread, "environment", &o_nil);
1707     addIntrinsicVar(class_thread, "exceptionHandler", &o_nil);
1708     addIntrinsicVar(class_thread, "threadPlayer", &o_nil);
1709 
1710     addIntrinsicVar(class_thread, "executingPath", &o_nil);
1711     addIntrinsicVar(class_thread, "oldExecutingPath", &o_nil);
1712 
1713     class_finalizer = makeIntrinsicClass(s_finalizer, s_object, 2, 0);
1714     addIntrinsicVar(class_finalizer, "cFunction", &o_nil);
1715     addIntrinsicVar(class_finalizer, "object", &o_nil);
1716 
1717     class_routine = makeIntrinsicClass(s_routine, s_thread, 0, 0);
1718 
1719     class_symbol = makeIntrinsicClass(s_symbol, s_object, 0, 0);
1720     class_nil = makeIntrinsicClass(s_nil, s_object, 0, 0);
1721 
1722     class_boolean = makeIntrinsicClass(s_boolean, s_object, 0, 0);
1723     class_true = makeIntrinsicClass(s_true, s_boolean, 0, 0);
1724     class_false = makeIntrinsicClass(s_false, s_boolean, 0, 0);
1725 
1726     class_magnitude = makeIntrinsicClass(s_magnitude, s_object, 0, 0);
1727     class_char = makeIntrinsicClass(s_char, s_magnitude, 0, 0);
1728     class_number = makeIntrinsicClass(s_number, s_magnitude, 0, 0);
1729     class_simple_number = makeIntrinsicClass(s_simple_number, s_number, 0, 0);
1730     class_int = makeIntrinsicClass(s_int, s_simple_number, 0, 0);
1731     class_float = makeIntrinsicClass(s_float, s_simple_number, 0, 0);
1732 
1733     class_rawptr = makeIntrinsicClass(s_rawptr, s_object, 0, 0);
1734 
1735     /*
1736         class_complex = makeIntrinsicClass(s_complex, s_number, 2, 0);
1737             addIntrinsicVar(class_complex, "real", &o_nil);
1738             addIntrinsicVar(class_complex, "imag", &o_nil);
1739     */
1740 
1741     class_rawarray = makeIntrinsicClass(s_rawarray, s_arrayed_collection, 0, 0);
1742     // SetInt(&class_rawarray->instanceFormat, obj_int8);
1743     // slotRawInt(&class_rawarray->classFlags) |= classHasIndexableInstances;
1744     class_int8array = makeIntrinsicClass(s_int8array, s_rawarray, 0, 0);
1745     SetInt(&class_int8array->instanceFormat, obj_int8);
1746     SetInt(&class_int8array->classFlags, slotRawInt(&class_int8array->classFlags) | classHasIndexableInstances);
1747     class_int16array = makeIntrinsicClass(s_int16array, s_rawarray, 0, 0);
1748     SetInt(&class_int16array->instanceFormat, obj_int16);
1749     SetInt(&class_int16array->classFlags, slotRawInt(&class_int16array->classFlags) | classHasIndexableInstances);
1750     class_int32array = makeIntrinsicClass(s_int32array, s_rawarray, 0, 0);
1751     SetInt(&class_int32array->instanceFormat, obj_int32);
1752     SetInt(&class_int32array->classFlags, slotRawInt(&class_int32array->classFlags) | classHasIndexableInstances);
1753     class_symbolarray = makeIntrinsicClass(s_symbolarray, s_rawarray, 0, 0);
1754     SetInt(&class_symbolarray->instanceFormat, obj_symbol);
1755     SetInt(&class_symbolarray->classFlags, slotRawInt(&class_symbolarray->classFlags) | classHasIndexableInstances);
1756     class_string = makeIntrinsicClass(s_string, s_rawarray, 0, 1);
1757     addIntrinsicClassVar(class_string, "unixCmdActions", &o_nil);
1758     SetInt(&class_string->instanceFormat, obj_char);
1759     SetInt(&class_string->classFlags, slotRawInt(&class_string->classFlags) | classHasIndexableInstances);
1760     class_floatarray = makeIntrinsicClass(s_floatarray, s_rawarray, 0, 0);
1761     SetInt(&class_floatarray->instanceFormat, obj_float);
1762     SetInt(&class_floatarray->classFlags, slotRawInt(&class_floatarray->classFlags) | classHasIndexableInstances);
1763     class_signal = makeIntrinsicClass(s_signal, s_floatarray, 0, 0);
1764     SetInt(&class_signal->instanceFormat, obj_float);
1765     SetInt(&class_signal->classFlags, slotRawInt(&class_signal->classFlags) | classHasIndexableInstances);
1766     class_wavetable = makeIntrinsicClass(s_wavetable, s_floatarray, 0, 0);
1767     SetInt(&class_wavetable->instanceFormat, obj_float);
1768     SetInt(&class_wavetable->classFlags, slotRawInt(&class_wavetable->classFlags) | classHasIndexableInstances);
1769 
1770     // addIntrinsicVar(class_signal, "rate", &o_nil);
1771     class_doublearray = makeIntrinsicClass(s_doublearray, s_rawarray, 0, 0);
1772     SetInt(&class_doublearray->instanceFormat, obj_double);
1773     SetInt(&class_doublearray->classFlags, slotRawInt(&class_doublearray->classFlags) | classHasIndexableInstances);
1774 
1775     class_list = makeIntrinsicClass(s_list, s_sequenceable_collection, 1, 0);
1776     addIntrinsicVar(class_list, "array", &o_nil);
1777     // addIntrinsicVar(class_list, "size", &o_zero);
1778 
1779     class_func = makeIntrinsicClass(s_func, s_absfunc, 2, 0);
1780     addIntrinsicVar(class_func, "def", &o_nil);
1781     addIntrinsicVar(class_func, "context", &o_nil);
1782 
1783     class_server_shm_interface = makeIntrinsicClass(s_server_shm_interface, s_object, 2, 0);
1784     addIntrinsicVar(class_server_shm_interface, "ptr", &o_nil);
1785     addIntrinsicVar(class_server_shm_interface, "finalizer", &o_nil);
1786 
1787     gTagClassTable[0] = nullptr;
1788     gTagClassTable[1] = nullptr;
1789     gTagClassTable[2] = class_int;
1790     gTagClassTable[3] = class_symbol;
1791     gTagClassTable[4] = class_char;
1792     gTagClassTable[5] = class_nil;
1793     gTagClassTable[6] = class_false;
1794     gTagClassTable[7] = class_true;
1795     gTagClassTable[8] = class_rawptr;
1796     gTagClassTable[9] = class_float;
1797     gTagClassTable[10] = class_float;
1798     gTagClassTable[11] = class_float;
1799     gTagClassTable[12] = class_float;
1800 
1801     SetObject(&o_emptyarray, newPyrArray(nullptr, 0, obj_permanent | obj_immutable, false));
1802 
1803     SetObject(&o_onenilarray, newPyrArray(nullptr, 1, obj_permanent | obj_immutable, false));
1804     slotRawObject(&o_onenilarray)->size = 1;
1805     SetNil(slotRawObject(&o_onenilarray)->slots);
1806 
1807     SetObject(&o_argnamethis, newPyrSymbolArray(nullptr, 1, obj_permanent | obj_immutable, false));
1808     slotRawSymbolArray(&o_argnamethis)->size = 1;
1809     slotRawSymbolArray(&o_argnamethis)->symbols[0] = s_this;
1810 
1811     /*
1812     post("array %p '%s'\n", class_array, class_array->name.us->name);
1813     post("o_emptyarray %p '%s'\n", slotRawObject(&o_emptyarray)->classptr,
1814     slotRawObject(&o_emptyarray)->classptr->name.us->name); post("o_argnamethis %p '%s'\n",
1815     slotRawObject(&o_argnamethis)->classptr, slotRawObject(&o_argnamethis)->classptr->name.us->name);
1816     post("o_onenilarray %p '%s'\n", slotRawObject(&o_onenilarray)->classptr,
1817     slotRawObject(&o_onenilarray)->classptr->name.us->name); dumpObjectSlot(&o_emptyarray);
1818     dumpObjectSlot(&o_argnamethis);
1819     dumpObjectSlot(&o_onenilarray);
1820     */
1821 }
1822 
instantiateObject(class PyrGC * gc,PyrClass * classobj,int size,bool fill,bool runGC)1823 PyrObject* instantiateObject(class PyrGC* gc, PyrClass* classobj, int size, bool fill, bool runGC) {
1824     PyrObject *newobj, *proto;
1825     int numbytes, format, flags;
1826 
1827     format = slotRawInt(&classobj->instanceFormat);
1828     flags = slotRawInt(&classobj->instanceFlags);
1829 
1830     if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
1831         // create an indexable object
1832         numbytes = size * gFormatElemSize[format];
1833         newobj = gc->New(numbytes, flags, format, runGC);
1834         if (fill) {
1835             newobj->size = size;
1836             if (format == obj_slot) {
1837                 nilSlots(newobj->slots, size);
1838             } else {
1839                 memset(newobj->slots, format == obj_char ? ' ' : 0, size * gFormatElemSize[format]);
1840             }
1841         } else {
1842             newobj->size = 0;
1843         }
1844     } else {
1845         if (IsObj(&classobj->iprototype)) {
1846             proto = slotRawObject(&classobj->iprototype);
1847             size = proto->size;
1848             numbytes = size * sizeof(PyrSlot);
1849             newobj = gc->New(numbytes, flags, format, runGC);
1850             newobj->size = size;
1851             if (size) {
1852                 memcpy(newobj->slots, proto->slots, numbytes);
1853             }
1854         } else {
1855             numbytes = 0;
1856             newobj = gc->New(numbytes, flags, format, runGC);
1857             newobj->size = 0;
1858         }
1859     }
1860     newobj->classptr = classobj;
1861     return newobj;
1862 }
1863 
1864 PyrObject* instantiateObjectLight(class PyrGC* gc, PyrClass* classobj, int size, bool runGC);
instantiateObjectLight(class PyrGC * gc,PyrClass * classobj,int size,bool runGC)1865 PyrObject* instantiateObjectLight(class PyrGC* gc, PyrClass* classobj, int size, bool runGC) {
1866     PyrObject *newobj, *proto;
1867     int numbytes, format, flags;
1868 
1869     format = slotRawInt(&classobj->instanceFormat);
1870     flags = slotRawInt(&classobj->instanceFlags);
1871 
1872     if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
1873         numbytes = size * gFormatElemSize[format];
1874     } else {
1875         if (IsObj(&classobj->iprototype)) {
1876             proto = slotRawObject(&classobj->iprototype);
1877             size = proto->size;
1878             numbytes = size * sizeof(PyrSlot);
1879         } else {
1880             size = 0;
1881             numbytes = 0;
1882         }
1883     }
1884     newobj = gc->New(numbytes, flags, format, runGC);
1885     newobj->size = size;
1886     newobj->classptr = classobj;
1887 
1888     return newobj;
1889 }
1890 
copyObject(class PyrGC * gc,PyrObject * inobj,bool runGC)1891 PyrObject* copyObject(class PyrGC* gc, PyrObject* inobj, bool runGC) {
1892     PyrObject* newobj;
1893 
1894     // copies are neither immutable not permanent
1895     int flags = ~(obj_immutable)&inobj->obj_flags;
1896     flags = ~(obj_permanent)&flags;
1897 
1898     int elemsize = gFormatElemSize[inobj->obj_format];
1899     int numbytes = inobj->size * elemsize;
1900 
1901     newobj = gc->New(numbytes, flags, inobj->obj_format, runGC);
1902 
1903     newobj->size = inobj->size;
1904     newobj->classptr = inobj->classptr;
1905 
1906     memcpy(newobj->slots, inobj->slots, inobj->size * elemsize);
1907     return newobj;
1908 }
1909 
copyObjectRange(class PyrGC * gc,PyrObject * inobj,int start,int end,bool runGC)1910 PyrObject* copyObjectRange(class PyrGC* gc, PyrObject* inobj, int start, int end, bool runGC) {
1911     PyrObject* newobj;
1912 
1913     if (start < 0)
1914         start = 0;
1915     if (end >= inobj->size)
1916         end = inobj->size - 1;
1917     int length = end - start + 1;
1918     if (length < 0)
1919         length = 0;
1920 
1921     int elemsize = gFormatElemSize[inobj->obj_format];
1922     int numbytes = length * elemsize;
1923 
1924     // copies are neither immutable not permanent
1925     int flags = ~(obj_immutable)&inobj->obj_flags;
1926     flags = ~(obj_permanent)&flags;
1927 
1928     newobj = gc->New(numbytes, flags, inobj->obj_format, runGC);
1929     newobj->size = length;
1930     newobj->classptr = inobj->classptr;
1931 
1932     if (length > 0) {
1933         memcpy(newobj->slots, (char*)(inobj->slots) + start * elemsize, length * elemsize);
1934     }
1935     return newobj;
1936 }
1937 
dumpObject(PyrObject * obj)1938 void dumpObject(PyrObject* obj) {
1939     char str[256];
1940     PyrClass* classobj;
1941     int i;
1942 
1943     if (obj == nullptr) {
1944         postfl("NULL object pointer\n");
1945         return;
1946     }
1947     classobj = obj->classptr;
1948     if (isKindOf(obj, class_class)) {
1949         post("class %s (%p) {\n", slotRawSymbol(&((PyrClass*)obj)->name)->name, obj);
1950     } else {
1951         // post("Instance of %s (%p) {\n", slotRawSymbol(&classobj->name)->name, obj);
1952         post("Instance of %s {    (%p, gc=%02X, fmt=%02X, flg=%02X, set=%02X)\n", slotRawSymbol(&classobj->name)->name,
1953              obj, obj->gc_color, obj->obj_format, obj->obj_flags, obj->obj_sizeclass);
1954     }
1955     // flushPostBuf();
1956 
1957     if (obj->obj_format == obj_notindexed) {
1958         post("  instance variables [%d]\n", obj->size);
1959         for (i = 0; i < obj->size; ++i) {
1960             slotString(obj->slots + i, str);
1961             post("    %s : %s\n", slotRawSymbolArray(&classobj->instVarNames)->symbols[i]->name, str);
1962         }
1963     } else {
1964         int maxsize;
1965         post("  indexed slots [%d]\n", obj->size);
1966         maxsize = sc_min(32, obj->size);
1967         switch (obj->obj_format) {
1968         case obj_slot:
1969             for (i = 0; i < maxsize; ++i) {
1970                 slotString(obj->slots + i, str);
1971                 post("    %3d : %s\n", i, str);
1972             }
1973             break;
1974         case obj_double:
1975             for (i = 0; i < maxsize; ++i) {
1976                 post("    %3d : %f\n", i, slotRawFloat(&obj->slots[i]));
1977             }
1978             break;
1979         case obj_float:
1980             for (i = 0; i < maxsize; ++i) {
1981                 float val;
1982                 val = ((float*)(obj->slots))[i];
1983                 post("    %3d : %g\n", i, val);
1984             }
1985             break;
1986         case obj_int32:
1987             for (i = 0; i < maxsize; ++i) {
1988                 int32 val;
1989                 val = ((int32*)(obj->slots))[i];
1990                 post("    %3d : %d\n", i, val);
1991             }
1992             break;
1993         case obj_int16:
1994             for (i = 0; i < maxsize; ++i) {
1995                 int16 val;
1996                 val = ((int16*)(obj->slots))[i];
1997                 post("    %3d : %d\n", i, val);
1998             }
1999             break;
2000         case obj_int8:
2001             for (i = 0; i < maxsize; ++i) {
2002                 int8 val;
2003                 val = ((int8*)(obj->slots))[i];
2004                 post("    %3d : %4d %4u 0x%02X\n", i, val, val & 255, val & 255);
2005             }
2006             break;
2007         case obj_char:
2008             for (i = 0; i < maxsize; ++i) {
2009                 char val;
2010                 val = ((char*)(obj->slots))[i];
2011                 post("    %3d : %c\n", i, val);
2012             }
2013             break;
2014         case obj_symbol:
2015             for (i = 0; i < maxsize; ++i) {
2016                 PyrSymbol* sym;
2017                 sym = ((PyrSymbol**)(obj->slots))[i];
2018                 post("    %3d : '%s'\n", i, sym->name);
2019             }
2020             break;
2021         default:
2022             post("unknown obj_format %X\n", obj->obj_format);
2023         }
2024         if (obj->size > maxsize) {
2025             post("    ...\n");
2026         }
2027     }
2028     post("}\n");
2029 }
2030 
dumpBadObject(PyrObject * obj)2031 void dumpBadObject(PyrObject* obj) {
2032     char str[128];
2033     PyrClass* classobj;
2034     int i;
2035 
2036     if (obj == nullptr) {
2037         postfl("NULL object pointer\n");
2038         return;
2039     }
2040     classobj = obj->classptr;
2041     if (isKindOf(obj, class_class)) {
2042         postfl("class %s (%p) {\n", slotRawSymbol(&((PyrClass*)obj)->name)->name, obj);
2043     } else {
2044         // postfl("Instance of %s (%p) {\n", slotRawSymbol(&classobj->name)->name, obj);
2045         postfl("Instance of %s {    (%p, gc=%02X, fmt=%02X, flg=%02X, set=%02X)\n",
2046                slotRawSymbol(&classobj->name)->name, obj, obj->gc_color, obj->obj_format, obj->obj_flags,
2047                obj->obj_sizeclass);
2048     }
2049     if (obj->obj_format == obj_notindexed) {
2050         postfl("  instance variables [%d]\n", obj->size);
2051         for (i = 0; i < obj->size; ++i) {
2052             slotString(obj->slots + i, str);
2053             postfl("    %s : %s\n", slotRawSymbolArray(&classobj->instVarNames)->symbols[i]->name, str);
2054         }
2055     } else {
2056         int maxsize;
2057         postfl("  indexed slots [%d]\n", obj->size);
2058         maxsize = obj->size;
2059         maxsize = sc_min(32, maxsize);
2060         switch (obj->obj_format) {
2061         case obj_slot:
2062             for (i = 0; i < maxsize; ++i) {
2063                 slotString(obj->slots + i, str);
2064                 postfl("    %3d : %s\n", i, str);
2065             }
2066             break;
2067         case obj_double:
2068             for (i = 0; i < maxsize; ++i) {
2069                 postfl("    %3d : %f\n", i, slotRawFloat(&obj->slots[i]));
2070             }
2071             break;
2072         case obj_float:
2073             for (i = 0; i < maxsize; ++i) {
2074                 float val;
2075                 val = ((float*)(obj->slots))[i];
2076                 postfl("    %3d : %g\n", i, val);
2077             }
2078             break;
2079         case obj_int32:
2080             for (i = 0; i < maxsize; ++i) {
2081                 int32 val;
2082                 val = ((int32*)(obj->slots))[i];
2083                 postfl("    %3d : %d\n", i, val);
2084             }
2085             break;
2086         case obj_int16:
2087             for (i = 0; i < maxsize; ++i) {
2088                 int16 val;
2089                 val = ((int16*)(obj->slots))[i];
2090                 postfl("    %3d : %d\n", i, val);
2091             }
2092             break;
2093         case obj_int8:
2094             for (i = 0; i < maxsize; ++i) {
2095                 int8 val;
2096                 val = ((int8*)(obj->slots))[i];
2097                 postfl("    %3d : %4d %4u 0x%02X\n", i, val, val & 255, val & 255);
2098             }
2099             break;
2100         case obj_char:
2101             for (i = 0; i < maxsize; ++i) {
2102                 char val;
2103                 val = ((char*)(obj->slots))[i];
2104                 postfl("    %3d : %c\n", i, val);
2105             }
2106             break;
2107         case obj_symbol:
2108             for (i = 0; i < maxsize; ++i) {
2109                 PyrSymbol* sym;
2110                 sym = ((PyrSymbol**)(obj->slots))[i];
2111                 post("    %3d : '%s'\n", i, sym->name);
2112             }
2113             break;
2114         default:
2115             postfl("unknown obj_format %X\n", obj->obj_format);
2116         }
2117         if (obj->size > maxsize) {
2118             postfl("    ...\n");
2119         }
2120     }
2121     postfl("}\n");
2122 }
2123 
dumpObjectSlot(PyrSlot * slot)2124 void dumpObjectSlot(PyrSlot* slot) {
2125     if (IsObj(slot)) {
2126         dumpObject(slotRawObject(slot));
2127     } else {
2128         dumpPyrSlot(slot);
2129     }
2130 }
2131 
dumpSlotOneWord(const char * tagstr,PyrSlot * slot)2132 void dumpSlotOneWord(const char* tagstr, PyrSlot* slot) {
2133     char str[256];
2134     slotOneWord(slot, str);
2135     post("%s %s\n", tagstr, str);
2136 }
2137 
2138 void CallStackSanity(VMGlobals* g, const char* tagstr);
CallStackSanity(VMGlobals * g,const char * tagstr)2139 void CallStackSanity(VMGlobals* g, const char* tagstr) {
2140     PyrFrame* frame;
2141     frame = g->frame;
2142     while (frame) {
2143         if (FrameSanity(frame, tagstr)) {
2144             DumpBackTrace(g);
2145             // Debugger();
2146             break;
2147         }
2148         frame = slotRawFrame(&frame->caller);
2149     }
2150 }
2151 
2152 bool FrameSanity(PyrFrame* frame, const char* tagstr);
FrameSanity(PyrFrame * frame,const char * tagstr)2153 bool FrameSanity(PyrFrame* frame, const char* tagstr) {
2154     bool failed = false;
2155     if (frame == nullptr)
2156         return false;
2157     if (NotObj(&frame->method)) {
2158         postfl("Frame %p method tag wrong %p\n", frame, GetTag(&frame->method));
2159         failed = true;
2160         //} else if (!isKindOf((PyrObject*)slotRawObject(&frame->method)->classptr, class_fundef)) {
2161     } else if (slotRawObject(&frame->method)->classptr != class_method
2162                && slotRawObject(&frame->method)->classptr != class_fundef) {
2163         postfl("Frame %p method class wrong %p\n", frame, slotRawObject(&frame->method)->classptr);
2164         failed = true;
2165         // if (slotRawObject(&frame->method)->classptr->classptr == class_class) {
2166         postfl("class: '%s'\n", slotRawSymbol(&slotRawObject(&frame->method)->classptr->name)->name);
2167         ///} else {
2168         //	postfl("not even a class\n");
2169         //}
2170     } else if (NotObj(&slotRawBlock(&frame->method)->code)) {
2171         postfl("Method %p code tag wrong %p\n", slotRawBlock(&frame->method),
2172                GetTag(&slotRawBlock(&frame->method)->code));
2173         failed = true;
2174     } else if (slotRawObject(&slotRawBlock(&frame->method)->code)->classptr != class_int8array) {
2175         postfl("Code %p class wrong %p\n", slotRawObject(&slotRawBlock(&frame->method)->code),
2176                slotRawObject(&slotRawBlock(&frame->method)->code)->classptr);
2177         postfl("class: '%s'\n",
2178                slotRawSymbol(&slotRawObject(&slotRawBlock(&frame->method)->code)->classptr->name)->name);
2179         failed = true;
2180     }
2181     /*
2182     if (frame->caller.utag != tagHFrame && frame->caller.utag != tagNil) {
2183         postfl("Frame %p caller tag wrong %p\n", frame, frame->caller.utag);
2184         failed = true;
2185     }
2186     if (frame->context.utag != tagHFrame && frame->context.utag != tagNil) {
2187         postfl("Frame %p context tag wrong %p\n", frame, frame->context.utag);
2188         failed = true;
2189     }
2190     if (frame->homeContext.utag != tagHFrame && frame->homeContext.utag != tagNil) {
2191         postfl("Frame %p homeContext tag wrong %p\n", frame, frame->homeContext.utag);
2192         failed = true;
2193     }
2194     */
2195     if (!IsPtr(&frame->ip)) {
2196         postfl("Frame %p ip tag wrong %p\n", frame, GetTag(&frame->ip));
2197         failed = true;
2198     }
2199     return failed;
2200 }
2201 
DumpFrame(PyrFrame * frame)2202 void DumpFrame(PyrFrame* frame) {
2203     char str[256];
2204     int i, numargs;
2205     PyrMethod* meth;
2206     PyrMethodRaw* methraw;
2207 
2208     if (FrameSanity(frame, "DumpFrame")) {
2209         post("FRAME CORRUPTED\n");
2210         return;
2211     }
2212     slotOneWord(&frame->method, str);
2213     // slotString(&frame->method, str);
2214 
2215     meth = slotRawMethod(&frame->method);
2216     methraw = METHRAW(meth);
2217     if (methraw->numtemps) {
2218         post("\t%s\n", str);
2219         numargs = methraw->numargs + methraw->varargs;
2220         for (i = 0; i < methraw->numtemps; ++i) {
2221             slotOneWord(frame->vars + i, str);
2222             // slotString(frame->vars + i, str);
2223             if (i < numargs) {
2224                 post("\t\targ %s = %s\n", slotRawSymbolArray(&meth->argNames)->symbols[i]->name, str);
2225             } else {
2226                 post("\t\tvar %s = %s\n", slotRawSymbolArray(&meth->varNames)->symbols[i - numargs]->name, str);
2227             }
2228         }
2229     } else {
2230         post("\t%s  (no arguments or variables)\n", str);
2231     }
2232 }
2233 
2234 void dumpByteCodes(PyrBlock* theBlock);
2235 
2236 void DumpDetailedFrame(PyrFrame* frame);
DumpDetailedFrame(PyrFrame * frame)2237 void DumpDetailedFrame(PyrFrame* frame) {
2238     char mstr[256];
2239     char str[256];
2240     int i, numargs;
2241     PyrMethod* meth;
2242     PyrMethodRaw* methraw;
2243 
2244     if (FrameSanity(frame, "DumpDetailedFrame")) {
2245         post("FRAME CORRUPTED\n");
2246         return;
2247     }
2248     slotOneWord(&frame->method, mstr);
2249     // slotString(&frame->method, str);
2250 
2251     meth = slotRawMethod(&frame->method);
2252     methraw = METHRAW(meth);
2253 
2254     if (methraw->numtemps) {
2255         post("\t%s\n", mstr);
2256         numargs = methraw->numargs + methraw->varargs;
2257         for (i = 0; i < methraw->numtemps; ++i) {
2258             slotOneWord(frame->vars + i, str);
2259             // slotString(frame->vars + i, str);
2260             if (i < numargs) {
2261                 post("\t\targ %s = %s\n", slotRawSymbolArray(&meth->argNames)->symbols[i]->name, str);
2262             } else {
2263                 post("\t\tvar %s = %s\n", slotRawSymbolArray(&meth->varNames)->symbols[i - numargs]->name, str);
2264             }
2265         }
2266     } else {
2267         post("\t%s  (no arguments or variables)\n", mstr);
2268     }
2269 
2270     post("\t....%s details:\n", mstr);
2271     post("\t\tneedsHeapContext  = %d\n", methraw->needsHeapContext);
2272     post("\t\tnumtemps  = %d\n", methraw->numtemps);
2273     post("\t\tpopSize  = %d\n", methraw->popSize);
2274 
2275     slotString(&frame->method, str);
2276     post("\t\tmethod  = %s\n", str);
2277     slotString(&frame->caller, str);
2278     post("\t\tcaller  = %s\n", str);
2279     slotString(&frame->context, str);
2280     post("\t\tcontext = %s\n", str);
2281     slotString(&frame->homeContext, str);
2282     post("\t\thomeCtx = %s\n", str);
2283     slotString(&frame->ip, str);
2284     post("\t\tip      = %s\n", str);
2285 
2286     if (IsPtr(&frame->ip)) {
2287         post("ipoffset = %d\n", (char*)slotRawPtr(&frame->ip) - (char*)slotRawInt8Array(&meth->code)->b);
2288         dumpByteCodes(meth);
2289     }
2290 }
2291 
2292 
respondsTo(PyrSlot * slot,PyrSymbol * selector)2293 bool respondsTo(PyrSlot* slot, PyrSymbol* selector) {
2294     PyrClass* classobj;
2295     PyrMethod* meth;
2296     int index;
2297 
2298     classobj = classOfSlot(slot);
2299 
2300     index = slotRawInt(&classobj->classIndex) + selector->u.index;
2301     meth = gRowTable[index];
2302     return slotRawSymbol(&meth->name) == selector;
2303 }
2304 
2305 PyrMethod* methodLookup(PyrSlot* slot, PyrSymbol* selector);
methodLookup(PyrSlot * slot,PyrSymbol * selector)2306 PyrMethod* methodLookup(PyrSlot* slot, PyrSymbol* selector) {
2307     PyrClass* classobj;
2308     PyrMethod* meth;
2309     int index;
2310 
2311     classobj = classOfSlot(slot);
2312 
2313     index = slotRawInt(&classobj->classIndex) + selector->u.index;
2314     meth = gRowTable[index];
2315     return meth;
2316 }
2317 
2318 
isSubclassOf(PyrClass * classobj,PyrClass * testclass)2319 bool isSubclassOf(PyrClass* classobj, PyrClass* testclass) {
2320     while (classobj) {
2321         if (classobj == testclass) {
2322             return true;
2323         }
2324         classobj = slotRawSymbol(&classobj->superclass)->u.classobj;
2325     }
2326     return false;
2327 }
2328 
2329 /*bool isKindOf(PyrObjectHdr *obj, PyrClass *testclass)
2330 {
2331     int objClassIndex = slotRawInt(&obj->classptr->classIndex);
2332     return objClassIndex >= slotRawInt(&testclass->classIndex) && objClassIndex <=
2333 slotRawInt(&testclass->maxSubclassIndex);
2334 }*/
2335 
objAddIndexedSlot(PyrObject * obj,PyrSlot * slot)2336 bool objAddIndexedSlot(PyrObject* obj, PyrSlot* slot) {
2337     if (obj->size < ARRAYMAXINDEXSIZE(obj)) {
2338         slotCopy(&obj->slots[obj->size++], slot);
2339         return true;
2340     } else {
2341         return false;
2342     }
2343 }
2344 
objAddIndexedSymbol(PyrSymbolArray * obj,PyrSymbol * symbol)2345 bool objAddIndexedSymbol(PyrSymbolArray* obj, PyrSymbol* symbol) {
2346     if (obj->size < MAXINDEXSIZE((PyrObject*)obj)) {
2347         obj->symbols[obj->size++] = symbol;
2348         return true;
2349     } else {
2350         return false;
2351     }
2352 }
2353 
objAddIndexedObject(PyrObject * obj,PyrObject * obj2)2354 bool objAddIndexedObject(PyrObject* obj, PyrObject* obj2) {
2355     if (obj->size < ARRAYMAXINDEXSIZE(obj)) {
2356         SetObject(obj->slots + obj->size, obj2);
2357         obj->size++;
2358         return true;
2359     } else {
2360         return false;
2361     }
2362 }
2363 
fillSlots(PyrSlot * slot,int size,PyrSlot * fillslot)2364 void fillSlots(PyrSlot* slot, int size, PyrSlot* fillslot) {
2365     for (int i = 0; i != size; ++i)
2366         slotCopy(&slot[i], fillslot);
2367 }
2368 
nilSlots(PyrSlot * slot,int size)2369 void nilSlots(PyrSlot* slot, int size) { fillSlots(slot, size, &o_nil); }
2370 
zeroSlots(PyrSlot * slot,int size)2371 void zeroSlots(PyrSlot* slot, int size) {
2372     PyrSlot zero;
2373     SetTagRaw(&zero, 0);
2374     SetRaw(&zero, 0.0);
2375     fillSlots(slot, size, &zero);
2376 }
2377 
newPyrObject(class PyrGC * gc,size_t inNumBytes,int inFlags,int inFormat,bool inRunGC)2378 PyrObject* newPyrObject(class PyrGC* gc, size_t inNumBytes, int inFlags, int inFormat, bool inRunGC) {
2379     return gc->New(inNumBytes, inFlags, inFormat, inRunGC);
2380 }
2381 
newPyrArray(class PyrGC * gc,int size,int flags,bool runGC)2382 PyrObject* newPyrArray(class PyrGC* gc, int size, int flags, bool runGC) {
2383     PyrObject* array;
2384 
2385     int numbytes = size * sizeof(PyrSlot);
2386     if (!gc)
2387         array = PyrGC::NewPermanent(numbytes, flags, obj_slot);
2388     else
2389         array = gc->New(numbytes, flags, obj_slot, runGC);
2390     array->classptr = class_array;
2391     return array;
2392 }
2393 
newPyrSymbolArray(class PyrGC * gc,int size,int flags,bool runGC)2394 PyrSymbolArray* newPyrSymbolArray(class PyrGC* gc, int size, int flags, bool runGC) {
2395     PyrSymbolArray* array;
2396 
2397     int numbytes = size * sizeof(PyrSymbol*);
2398     if (!gc)
2399         array = (PyrSymbolArray*)PyrGC::NewPermanent(numbytes, flags, obj_symbol);
2400     else
2401         array = (PyrSymbolArray*)gc->New(numbytes, flags, obj_symbol, runGC);
2402     array->classptr = class_symbolarray;
2403     return array;
2404 }
2405 
newPyrInt8Array(class PyrGC * gc,int size,int flags,bool runGC)2406 PyrInt8Array* newPyrInt8Array(class PyrGC* gc, int size, int flags, bool runGC) {
2407     PyrInt8Array* array;
2408 
2409     if (!gc)
2410         array = (PyrInt8Array*)PyrGC::NewPermanent(size, flags, obj_int8);
2411     else
2412         array = (PyrInt8Array*)gc->New(size, flags, obj_int8, runGC);
2413     array->classptr = class_int8array;
2414     return array;
2415 }
2416 
newPyrInt32Array(class PyrGC * gc,int size,int flags,bool runGC)2417 PyrInt32Array* newPyrInt32Array(class PyrGC* gc, int size, int flags, bool runGC) {
2418     PyrInt32Array* array;
2419     int numbytes = size * sizeof(int32);
2420     if (!gc)
2421         array = (PyrInt32Array*)PyrGC::NewPermanent(numbytes, flags, obj_int32);
2422     else
2423         array = (PyrInt32Array*)gc->New(numbytes, flags, obj_int32, runGC);
2424     array->classptr = class_int32array;
2425     return array;
2426 }
2427 
newPyrDoubleArray(class PyrGC * gc,int size,int flags,bool runGC)2428 PyrDoubleArray* newPyrDoubleArray(class PyrGC* gc, int size, int flags, bool runGC) {
2429     PyrDoubleArray* array;
2430 
2431     int numbytes = size * sizeof(double);
2432     if (!gc)
2433         array = (PyrDoubleArray*)PyrGC::NewPermanent(numbytes, flags, obj_double);
2434     else
2435         array = (PyrDoubleArray*)gc->New(size, flags, obj_double, runGC);
2436     array->classptr = class_doublearray;
2437     return array;
2438 }
2439 
newPyrString(class PyrGC * gc,const char * s,int flags,bool runGC)2440 PyrString* newPyrString(class PyrGC* gc, const char* s, int flags, bool runGC) {
2441     PyrString* string;
2442     int length = strlen(s);
2443 
2444     if (!gc)
2445         string = (PyrString*)PyrGC::NewPermanent(length, flags, obj_char);
2446     else
2447         string = (PyrString*)gc->New(length, flags, obj_char, runGC);
2448     string->classptr = class_string;
2449     string->size = length;
2450     memcpy(string->s, s, length);
2451     return string;
2452 }
2453 
newPyrStringN(class PyrGC * gc,int length,int flags,bool runGC)2454 PyrString* newPyrStringN(class PyrGC* gc, int length, int flags, bool runGC) {
2455     PyrString* string;
2456 
2457     if (!gc)
2458         string = (PyrString*)PyrGC::NewPermanent(length, flags, obj_char);
2459     else
2460         string = (PyrString*)gc->New(length, flags, obj_char, runGC);
2461     string->classptr = class_string;
2462     string->size = length; // filled with garbage!
2463     return string;
2464 }
2465 
newPyrBlock(int flags)2466 PyrBlock* newPyrBlock(int flags) {
2467     PyrBlock* block;
2468     PyrMethodRaw* methraw;
2469 
2470 
2471     int32 numbytes = sizeof(PyrBlock) - sizeof(PyrObjectHdr);
2472     int32 numSlots = numbytes / sizeof(PyrSlot);
2473 
2474     if (!compilingCmdLine)
2475         block = (PyrBlock*)PyrGC::NewPermanent(numbytes, flags, obj_notindexed);
2476     else
2477         block = (PyrBlock*)gMainVMGlobals->gc->New(numbytes, flags, obj_notindexed, false);
2478     block->classptr = class_fundef;
2479     block->size = numSlots;
2480 
2481     // clear out raw area
2482     methraw = METHRAW(block);
2483     methraw->specialIndex = 0;
2484     methraw->methType = methBlock;
2485     methraw->needsHeapContext = 0;
2486     methraw->frameSize = 0;
2487     methraw->varargs = 0;
2488     methraw->numargs = 0;
2489     methraw->numvars = 0;
2490     methraw->numtemps = 0;
2491     methraw->popSize = 0;
2492 
2493     nilSlots(&block->rawData1, numSlots);
2494     return block;
2495 }
2496 
scGlobals()2497 SCLANG_DLLEXPORT_C struct VMGlobals* scGlobals() { return gMainVMGlobals; }
2498 
initPyrMethod(PyrMethod * method)2499 PyrMethod* initPyrMethod(PyrMethod* method) {
2500     int32 numbytes = sizeof(PyrMethod) - sizeof(PyrObjectHdr);
2501     int32 numSlots = numbytes / sizeof(PyrSlot);
2502 
2503     method->classptr = class_method;
2504     method->size = 0;
2505     method->size = numSlots;
2506     SetFloat(&method->rawData1, 0.0);
2507     SetFloat(&method->rawData2, 0.0);
2508     nilSlots(&method->code, numSlots - 2);
2509     // slotCopy(&method->byteMeter, &o_zero);
2510     // slotCopy(&method->callMeter, &o_zero);
2511     // post("<- newPyrMethod %p %p\n", method, methraw);
2512     return method;
2513 }
2514 
newPyrMethod()2515 PyrMethod* newPyrMethod() {
2516     int32 numbytes = sizeof(PyrMethod) - sizeof(PyrObjectHdr);
2517     PyrMethod* method = (PyrMethod*)PyrGC::NewPermanent(numbytes, obj_permanent | obj_immutable, obj_notindexed);
2518     return initPyrMethod(method);
2519 }
2520 
freePyrSlot(PyrSlot * slot)2521 void freePyrSlot(PyrSlot* slot) {
2522     if (IsObj(slot)) {
2523         PyrObject* obj = slotRawObject(slot);
2524 
2525         if (obj && obj->IsPermanent()) {
2526             // don't deallocate these
2527             if (obj != slotRawObject(&o_emptyarray) && obj != slotRawObject(&o_onenilarray)
2528                 && obj != slotRawObject(&o_argnamethis))
2529                 pyr_pool_runtime->Free((void*)obj);
2530 
2531             SetNil(slot);
2532         }
2533     }
2534 }
2535 
freePyrObject(PyrObject * obj)2536 void freePyrObject(PyrObject* obj) {
2537     if (obj->IsPermanent()) {
2538         pyr_pool_runtime->Free((void*)obj);
2539     }
2540 }
2541 
getIndexedInt(PyrObject * obj,int index,int * value)2542 int getIndexedInt(PyrObject* obj, int index, int* value) {
2543     PyrSlot* slot;
2544     int err = errNone;
2545     if (index < 0 || index >= obj->size)
2546         return errIndexOutOfRange;
2547     switch (obj->obj_format) {
2548     case obj_slot:
2549         slot = obj->slots + index;
2550         if (IsFloat(slot)) {
2551             *value = (int)slotRawFloat(slot);
2552         } else if (IsInt(slot)) {
2553             *value = slotRawInt(slot);
2554         } else {
2555             err = errWrongType;
2556         }
2557         break;
2558     case obj_double:
2559         *value = (int)((double*)(obj->slots))[index];
2560         break;
2561     case obj_float:
2562         *value = (int)((float*)(obj->slots))[index];
2563         break;
2564     case obj_int32:
2565         *value = ((int32*)(obj->slots))[index];
2566         break;
2567     case obj_int16:
2568         *value = ((int16*)(obj->slots))[index];
2569         break;
2570     case obj_int8:
2571         *value = ((int8*)(obj->slots))[index];
2572         break;
2573     default:
2574         err = errWrongType;
2575     }
2576     return err;
2577 }
2578 
getIndexedFloat(PyrObject * obj,int index,float * value)2579 int getIndexedFloat(PyrObject* obj, int index, float* value) {
2580     PyrSlot* slot;
2581     int err = errNone;
2582     if (index < 0 || index >= obj->size)
2583         return errIndexOutOfRange;
2584     switch (obj->obj_format) {
2585     case obj_slot:
2586         slot = obj->slots + index;
2587         if (IsFloat(slot)) {
2588             *value = slotRawFloat(slot);
2589         } else if (IsInt(slot)) {
2590             *value = slotRawInt(slot);
2591         } else {
2592             err = errWrongType;
2593         }
2594         break;
2595     case obj_double:
2596         *value = ((double*)(obj->slots))[index];
2597         break;
2598     case obj_float:
2599         *value = ((float*)(obj->slots))[index];
2600         break;
2601     case obj_int32:
2602         *value = ((int32*)(obj->slots))[index];
2603         break;
2604     case obj_int16:
2605         *value = ((int16*)(obj->slots))[index];
2606         break;
2607     case obj_int8:
2608         *value = ((int8*)(obj->slots))[index];
2609         break;
2610     default:
2611         err = errWrongType;
2612     }
2613     return err;
2614 }
2615 
getIndexedDouble(PyrObject * obj,int index,double * value)2616 int getIndexedDouble(PyrObject* obj, int index, double* value) {
2617     PyrSlot* slot;
2618     int err = errNone;
2619     if (index < 0 || index >= obj->size)
2620         return errIndexOutOfRange;
2621     switch (obj->obj_format) {
2622     case obj_slot:
2623         slot = obj->slots + index;
2624         if (IsFloat(slot)) {
2625             *value = slotRawFloat(slot);
2626         } else if (IsInt(slot)) {
2627             *value = slotRawInt(slot);
2628         } else {
2629             err = errWrongType;
2630         }
2631         break;
2632     case obj_double:
2633         *value = ((double*)(obj->slots))[index];
2634         break;
2635     case obj_float:
2636         *value = ((float*)(obj->slots))[index];
2637         break;
2638     case obj_int32:
2639         *value = ((int32*)(obj->slots))[index];
2640         break;
2641     case obj_int16:
2642         *value = ((int16*)(obj->slots))[index];
2643         break;
2644     case obj_int8:
2645         *value = ((int8*)(obj->slots))[index];
2646         break;
2647     default:
2648         err = errWrongType;
2649     }
2650     return err;
2651 }
2652 
2653 
getIndexedSlot(PyrObject * obj,PyrSlot * a,int index)2654 void getIndexedSlot(PyrObject* obj, PyrSlot* a, int index) {
2655     //	postfl("getIndexedSlot %s %X %d\n", slotRawSymbol(&obj->classptr->name)->name,
2656     //		obj, index);
2657     switch (obj->obj_format) {
2658     case obj_slot:
2659         slotCopy(a, &obj->slots[index]);
2660         break;
2661     case obj_double:
2662         SetFloat(a, ((double*)(obj->slots))[index]);
2663         break;
2664     case obj_float:
2665         SetFloat(a, ((float*)(obj->slots))[index]);
2666         break;
2667     case obj_int32:
2668         SetInt(a, ((int32*)(obj->slots))[index]);
2669         break;
2670     case obj_int16:
2671         SetInt(a, ((int16*)(obj->slots))[index]);
2672         break;
2673     case obj_int8:
2674         SetInt(a, ((int8*)(obj->slots))[index]);
2675         break;
2676     case obj_symbol:
2677         SetSymbol(a, (PyrSymbol*)((int**)(obj->slots))[index]);
2678         break;
2679     case obj_char:
2680         SetChar(a, ((unsigned char*)(obj->slots))[index]);
2681         break;
2682     }
2683 }
2684 
putIndexedSlot(VMGlobals * g,PyrObject * obj,PyrSlot * c,int index)2685 int putIndexedSlot(VMGlobals* g, PyrObject* obj, PyrSlot* c, int index) {
2686     PyrSlot* slot;
2687     switch (obj->obj_format) {
2688     case obj_slot:
2689         if (obj->IsImmutable())
2690             return errImmutableObject;
2691         slot = obj->slots + index;
2692         slotCopy(slot, c);
2693         g->gc->GCWrite(obj, slot);
2694         break;
2695     case obj_double:
2696         if (NotFloat(c)) {
2697             if (NotInt(c))
2698                 return errWrongType;
2699             else {
2700                 ((double*)(obj->slots))[index] = slotRawInt(c);
2701             }
2702         } else
2703             ((double*)(obj->slots))[index] = slotRawFloat(c);
2704         break;
2705     case obj_float:
2706         if (NotFloat(c)) {
2707             if (NotInt(c))
2708                 return errWrongType;
2709             else {
2710                 ((float*)(obj->slots))[index] = slotRawInt(c);
2711             }
2712         } else
2713             ((float*)(obj->slots))[index] = slotRawFloat(c);
2714         break;
2715     case obj_int32:
2716         if (NotInt(c))
2717             return errWrongType;
2718         ((int32*)(obj->slots))[index] = slotRawInt(c);
2719         break;
2720     case obj_int16:
2721         if (NotInt(c))
2722             return errWrongType;
2723         ((int16*)(obj->slots))[index] = slotRawInt(c);
2724         break;
2725     case obj_int8:
2726         if (NotInt(c))
2727             return errWrongType;
2728         ((int8*)(obj->slots))[index] = slotRawInt(c);
2729         break;
2730     case obj_symbol:
2731         if (NotSym(c))
2732             return errWrongType;
2733         ((PyrSymbol**)(obj->slots))[index] = slotRawSymbol(c);
2734         break;
2735     case obj_char:
2736         if (NotChar(c))
2737             return errWrongType;
2738         ((unsigned char*)(obj->slots))[index] = slotRawChar(c);
2739         break;
2740     }
2741     return errNone;
2742 }
2743 
putIndexedFloat(PyrObject * obj,double val,int index)2744 int putIndexedFloat(PyrObject* obj, double val, int index) {
2745     PyrSlot* slot;
2746     switch (obj->obj_format) {
2747     case obj_slot:
2748         if (obj->IsImmutable())
2749             return errImmutableObject;
2750         slot = obj->slots + index;
2751         SetFloat(slot, val);
2752         break;
2753     case obj_double:
2754         ((double*)(obj->slots))[index] = val;
2755         break;
2756     case obj_float:
2757         ((float*)(obj->slots))[index] = (float)val;
2758         break;
2759     case obj_int32:
2760         ((int32*)(obj->slots))[index] = (int32)val;
2761         break;
2762     case obj_int16:
2763         ((int16*)(obj->slots))[index] = (int16)val;
2764         break;
2765     case obj_int8:
2766         ((int8*)(obj->slots))[index] = (int8)val;
2767         break;
2768     }
2769     return errNone;
2770 }
2771 /**
2772  * @brief obtain a vector of strings from an sclang collection of sclang strings.
2773  * @param coll The sclang collection containing strings
2774  * @return a tuple containing an int (the error code) and a vector of std:string's.
2775  * If an error occurs an empty vector is returned.
2776  */
PyrCollToVectorStdString(PyrObject * coll)2777 std::tuple<int, std::vector<std::string>> PyrCollToVectorStdString(PyrObject* coll) {
2778     std::vector<std::string> strings;
2779     for (int i = 0; i < coll->size; ++i) {
2780         PyrSlot argSlot;
2781         getIndexedSlot(coll, &argSlot, i);
2782         int error;
2783         std::string string;
2784         std::tie(error, string) = slotStrStdStrVal(&argSlot);
2785         if (error != errNone) {
2786             strings.clear();
2787             return std::make_tuple(error, strings);
2788         }
2789         strings.push_back(std::move(string));
2790     }
2791     return make_tuple(errNone, std::move(strings));
2792 }
2793 
hashPtr(void * ptr)2794 static int hashPtr(void* ptr) {
2795     int32 hashed_part = int32((size_t)ptr & 0xffffffff);
2796     return Hash(hashed_part);
2797 }
2798 
2799 int calcHash(PyrSlot* a);
calcHash(PyrSlot * a)2800 int calcHash(PyrSlot* a) {
2801     int hash;
2802     switch (GetTag(a)) {
2803     case tagObj:
2804         hash = hashPtr(slotRawObject(a));
2805         break;
2806     case tagInt:
2807         hash = Hash(slotRawInt(a));
2808         break;
2809     case tagChar:
2810         hash = Hash(slotRawChar(a) & 255);
2811         break;
2812     case tagSym:
2813         hash = slotRawSymbol(a)->hash;
2814         break;
2815     case tagNil:
2816         hash = 0xA5A5A5A5;
2817         break;
2818     case tagFalse:
2819         hash = 0x55AA55AA;
2820         break;
2821     case tagTrue:
2822         hash = 0x69696969;
2823         break;
2824     case tagPtr:
2825         hash = hashPtr(slotRawPtr(a));
2826         break;
2827     default:
2828         // hash for a double
2829         union {
2830             int32 i[2];
2831             double d;
2832         } u;
2833         u.d = slotRawFloat(a);
2834         hash = Hash(u.i[0] + Hash(u.i[1]));
2835     }
2836     return hash;
2837 }
2838 
InstallFinalizer(VMGlobals * g,PyrObject * inObj,int slotIndex,ObjFuncPtr inFunc)2839 void InstallFinalizer(VMGlobals* g, PyrObject* inObj, int slotIndex, ObjFuncPtr inFunc) {
2840     PyrObject* finalizer = g->gc->NewFinalizer(inFunc, inObj, false);
2841     SetObject(inObj->slots + slotIndex, finalizer);
2842     g->gc->GCWriteNew(inObj, finalizer); // we know finalizer is white so we can use GCWriteNew
2843 }
2844