Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / lang / LangSource / PyrMessage.cpp
blobcc22d81f3b2c3591537e00654fb9fc99d17c3e81
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
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.
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.
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
21 #include "PyrMessage.h"
22 #include "PyrPrimitiveProto.h"
23 #include "PyrInterpreter.h"
24 #include "PyrPrimitive.h"
25 #include "PyrListPrim.h"
26 #include "PyrSymbol.h"
27 #include "GC.h"
28 #include <stdlib.h>
29 #include <assert.h>
30 #include "PredefinedSymbols.h"
31 #include "PyrObjectProto.h"
32 #include "SCBase.h"
34 #define DEBUGMETHODS 0
35 #define METHODMETER 0
37 PyrMethod **gRowTable;
39 PyrSlot keywordstack[MAXKEYSLOTS];
40 bool gKeywordError = true;
41 extern bool gTraceInterpreter;
43 long cvxUniqueMethods;
44 extern int ivxIdentDict_array;
46 void StoreToImmutableB(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip);
48 void initUniqueMethods()
50 PyrClass *dummyclass;
51 cvxUniqueMethods = classVarOffset("Object", "uniqueMethods", &dummyclass);
54 HOT void sendMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed)
56 PyrMethod *meth = NULL;
57 PyrMethodRaw *methraw;
58 PyrSlot *recvrSlot, *sp;
59 PyrClass *classobj;
60 long index;
61 PyrObject *obj;
63 //postfl("->sendMessage\n");
64 #ifdef GC_SANITYCHECK
65 g->gc->SanityCheck();
66 CallStackSanity(g, "sendMessageWithKeys");
67 #endif
68 recvrSlot = g->sp - numArgsPushed + 1;
70 classobj = classOfSlot(recvrSlot);
72 lookup_again:
73 index = slotRawInt(&classobj->classIndex) + selector->u.index;
74 meth = gRowTable[index];
76 if (slotRawSymbol(&meth->name) != selector) {
77 doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
78 } else {
79 methraw = METHRAW(meth);
80 //postfl("methraw->methType %d\n", methraw->methType);
81 switch (methraw->methType) {
82 case methNormal : /* normal msg send */
83 executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
84 break;
85 case methReturnSelf : /* return self */
86 g->sp -= numArgsPushed - 1;
87 break;
88 case methReturnLiteral : /* return literal */
89 sp = g->sp -= numArgsPushed - 1;
90 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
91 break;
92 case methReturnArg : /* return an argument */
93 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
94 numKeyArgsPushed = 0;
95 g->sp -= numArgsPushed - 1;
96 sp = g->sp;
97 index = methraw->specialIndex; // zero is index of the first argument
98 if (index < numArgsPushed) {
99 slotCopy(sp, sp + index);
100 } else {
101 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
103 break;
104 case methReturnInstVar : /* return inst var */
105 sp = g->sp -= numArgsPushed - 1;
106 index = methraw->specialIndex;
107 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
108 break;
109 case methAssignInstVar : /* assign inst var */
110 sp = g->sp -= numArgsPushed - 1;
111 index = methraw->specialIndex;
112 obj = slotRawObject(recvrSlot);
113 if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); }
114 else {
115 if (numArgsPushed >= 2) {
116 slotCopy(&obj->slots[index], sp + 1);
117 g->gc->GCWrite(obj, sp + 1);
118 } else {
119 SetNil(&obj->slots[index]);
121 slotCopy(sp, recvrSlot);
123 break;
124 case methReturnClassVar : /* return class var */
125 sp = g->sp -= numArgsPushed - 1;
126 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
127 break;
128 case methAssignClassVar : /* assign class var */
129 sp = g->sp -= numArgsPushed - 1;
130 if (numArgsPushed >= 2) {
131 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
132 g->gc->GCWrite(g->classvars, sp + 1);
133 } else {
134 SetNil(&g->classvars->slots[methraw->specialIndex]);
136 slotCopy(sp, recvrSlot);
137 break;
138 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
139 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
140 numKeyArgsPushed = 0;
141 selector = slotRawSymbol(&meth->selectors);
142 goto lookup_again;
143 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
144 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
145 numKeyArgsPushed = 0;
146 selector = slotRawSymbol(&meth->selectors);
147 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
148 goto lookup_again;
149 case methForwardInstVar : /* forward to an instance variable */
150 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
151 numKeyArgsPushed = 0;
152 selector = slotRawSymbol(&meth->selectors);
153 index = methraw->specialIndex;
154 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
156 classobj = classOfSlot(recvrSlot);
158 goto lookup_again;
159 case methForwardClassVar : /* forward to a class variable */
160 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
161 numKeyArgsPushed = 0;
162 selector = slotRawSymbol(&meth->selectors);
163 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
165 classobj = classOfSlot(recvrSlot);
167 goto lookup_again;
168 case methPrimitive : /* primitive */
169 doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
170 #ifdef GC_SANITYCHECK
171 g->gc->SanityCheck();
172 #endif
173 break;
176 #if TAILCALLOPTIMIZE
177 g->tailCall = 0;
178 #endif
179 #ifdef GC_SANITYCHECK
180 g->gc->SanityCheck();
181 CallStackSanity(g, "<sendMessageWithKeys");
182 #endif
183 //postfl("<-sendMessage\n");
187 HOT void sendMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed)
189 PyrMethod *meth = NULL;
190 PyrMethodRaw *methraw;
191 PyrSlot *recvrSlot, *sp;
192 PyrClass *classobj;
193 long index;
194 PyrObject *obj;
196 //postfl("->sendMessage\n");
197 #ifdef GC_SANITYCHECK
198 g->gc->SanityCheck();
199 CallStackSanity(g, "sendMessage");
200 #endif
201 recvrSlot = g->sp - numArgsPushed + 1;
203 classobj = classOfSlot(recvrSlot);
205 lookup_again:
206 index = slotRawInt(&classobj->classIndex) + selector->u.index;
207 meth = gRowTable[index];
209 if (slotRawSymbol(&meth->name) != selector) {
210 doesNotUnderstand(g, selector, numArgsPushed);
211 } else {
212 methraw = METHRAW(meth);
213 //postfl("methraw->methType %d\n", methraw->methType);
214 switch (methraw->methType) {
215 case methNormal : /* normal msg send */
216 executeMethod(g, meth, numArgsPushed);
217 break;
218 case methReturnSelf : /* return self */
219 g->sp -= numArgsPushed - 1;
220 break;
221 case methReturnLiteral : /* return literal */
222 sp = g->sp -= numArgsPushed - 1;
223 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
224 break;
225 case methReturnArg : /* return an argument */
226 sp = g->sp -= numArgsPushed - 1;
227 index = methraw->specialIndex; // zero is index of the first argument
228 if (index < numArgsPushed) {
229 slotCopy(sp, sp + index);
230 } else {
231 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
233 break;
234 case methReturnInstVar : /* return inst var */
235 sp = g->sp -= numArgsPushed - 1;
236 index = methraw->specialIndex;
237 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
238 break;
239 case methAssignInstVar : /* assign inst var */
240 sp = g->sp -= numArgsPushed - 1;
241 index = methraw->specialIndex;
242 obj = slotRawObject(recvrSlot);
243 if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); }
244 else {
245 if (numArgsPushed >= 2) {
246 slotCopy(&obj->slots[index], sp + 1);
247 g->gc->GCWrite(obj, sp + 1);
248 } else {
249 SetNil(&obj->slots[index]);
251 slotCopy(sp, recvrSlot);
253 break;
254 case methReturnClassVar : /* return class var */
255 sp = g->sp -= numArgsPushed - 1;
256 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
257 break;
258 case methAssignClassVar : /* assign class var */
259 sp = g->sp -= numArgsPushed - 1;
260 if (numArgsPushed >= 2) {
261 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
262 g->gc->GCWrite(g->classvars, sp + 1);
263 } else {
264 SetNil(&g->classvars->slots[methraw->specialIndex]);
266 slotCopy(sp, recvrSlot);
267 break;
268 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
269 if (numArgsPushed < methraw->numargs) { // not enough args pushed
270 /* push default arg values */
271 PyrSlot *pslot, *qslot;
272 long m, mmax;
273 pslot = g->sp;
274 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
275 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
276 numArgsPushed = methraw->numargs;
277 g->sp += mmax;
279 selector = slotRawSymbol(&meth->selectors);
280 goto lookup_again;
281 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
282 if (numArgsPushed < methraw->numargs) { // not enough args pushed
283 /* push default arg values */
284 PyrSlot *pslot, *qslot;
285 long m, mmax;
286 pslot = g->sp;
287 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
288 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
289 numArgsPushed = methraw->numargs;
290 g->sp += mmax;
292 selector = slotRawSymbol(&meth->selectors);
293 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
294 goto lookup_again;
295 case methForwardInstVar : /* forward to an instance variable */
296 if (numArgsPushed < methraw->numargs) { // not enough args pushed
297 /* push default arg values */
298 PyrSlot *pslot, *qslot;
299 long m, mmax;
300 pslot = g->sp;
301 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
302 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
303 numArgsPushed = methraw->numargs;
304 g->sp += mmax;
306 selector = slotRawSymbol(&meth->selectors);
307 index = methraw->specialIndex;
308 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
310 classobj = classOfSlot(recvrSlot);
312 goto lookup_again;
313 case methForwardClassVar : /* forward to a class variable */
314 if (numArgsPushed < methraw->numargs) { // not enough args pushed
315 /* push default arg values */
316 PyrSlot *pslot, *qslot;
317 long m, mmax;
318 pslot = g->sp;
319 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
320 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
321 numArgsPushed = methraw->numargs;
322 g->sp += mmax;
324 selector = slotRawSymbol(&meth->selectors);
325 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
327 classobj = classOfSlot(recvrSlot);
329 goto lookup_again;
330 case methPrimitive : /* primitive */
331 doPrimitive(g, meth, numArgsPushed);
332 #ifdef GC_SANITYCHECK
333 g->gc->SanityCheck();
334 #endif
335 break;
337 case methMultDispatchByClass : {
338 index = methraw->specialIndex;
339 if (index < numArgsPushed) {
340 classobj = slotRawObject(sp + index)->classptr;
341 selector = slotRawSymbol(&meth->selectors);
342 goto lookup_again;
343 } else {
344 doesNotUnderstand(g, selector, numArgsPushed);
346 } break;
347 case methMultDispatchByValue : {
348 index = methraw->specialIndex;
349 if (index < numArgsPushed) {
350 index = arrayAtIdentityHashInPairs(array, b);
351 meth = slotRawObject(&meth->selectors)->slots[index + 1].uom;
352 goto meth_select_again;
353 } else {
354 doesNotUnderstand(g, selector, numArgsPushed);
356 } break;
361 #if TAILCALLOPTIMIZE
362 g->tailCall = 0;
363 #endif
364 #ifdef GC_SANITYCHECK
365 g->gc->SanityCheck();
366 CallStackSanity(g, "<sendMessage");
367 #endif
368 //postfl("<-sendMessage\n");
372 HOT void sendSuperMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed)
374 PyrMethod *meth = NULL;
375 PyrMethodRaw *methraw;
376 PyrSlot *recvrSlot, *sp;
377 PyrClass *classobj;
378 long index;
379 PyrObject *obj;
381 //postfl("->sendMessage\n");
382 #ifdef GC_SANITYCHECK
383 g->gc->SanityCheck();
384 CallStackSanity(g, "sendSuperMessageWithKeys");
385 #endif
386 recvrSlot = g->sp - numArgsPushed + 1;
388 classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
389 //assert(isKindOfSlot(recvrSlot, classobj));
391 lookup_again:
392 index = slotRawInt(&classobj->classIndex) + selector->u.index;
393 meth = gRowTable[index];
395 if (slotRawSymbol(&meth->name) != selector) {
396 doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
397 } else {
398 methraw = METHRAW(meth);
399 //postfl("methraw->methType %d\n", methraw->methType);
400 switch (methraw->methType) {
401 case methNormal : /* normal msg send */
402 executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
403 break;
404 case methReturnSelf : /* return self */
405 g->sp -= numArgsPushed - 1;
406 break;
407 case methReturnLiteral : /* return literal */
408 sp = g->sp -= numArgsPushed - 1;
409 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
410 break;
411 case methReturnArg : /* return an argument */
412 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
413 numKeyArgsPushed = 0;
414 g->sp -= numArgsPushed - 1;
415 sp = g->sp;
416 index = methraw->specialIndex; // zero is index of the first argument
417 if (index < numArgsPushed) {
418 slotCopy(sp, sp + index);
419 } else {
420 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
422 break;
423 case methReturnInstVar : /* return inst var */
424 sp = g->sp -= numArgsPushed - 1;
425 index = methraw->specialIndex;
426 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
427 break;
428 case methAssignInstVar : /* assign inst var */
429 sp = g->sp -= numArgsPushed - 1;
430 index = methraw->specialIndex;
431 obj = slotRawObject(recvrSlot);
432 if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); }
433 else {
434 if (numArgsPushed >= 2) {
435 slotCopy(&obj->slots[index], sp + 1);
436 g->gc->GCWrite(obj, sp + 1);
437 } else {
438 SetNil(&obj->slots[index]);
440 slotCopy(sp, recvrSlot);
442 break;
443 case methReturnClassVar : /* return class var */
444 sp = g->sp -= numArgsPushed - 1;
445 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
446 break;
447 case methAssignClassVar : /* assign class var */
448 sp = g->sp -= numArgsPushed - 1;
449 if (numArgsPushed >= 2) {
450 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
451 g->gc->GCWrite(g->classvars, sp + 1);
452 } else {
453 SetNil(&g->classvars->slots[methraw->specialIndex]);
455 slotCopy(sp, recvrSlot);
456 break;
457 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
458 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
459 numKeyArgsPushed = 0;
460 selector = slotRawSymbol(&meth->selectors);
461 goto lookup_again;
462 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
463 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
464 numKeyArgsPushed = 0;
465 selector = slotRawSymbol(&meth->selectors);
466 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
467 goto lookup_again;
468 case methForwardInstVar : /* forward to an instance variable */
469 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
470 numKeyArgsPushed = 0;
471 selector = slotRawSymbol(&meth->selectors);
472 index = methraw->specialIndex;
473 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
475 classobj = classOfSlot(recvrSlot);
477 goto lookup_again;
478 case methForwardClassVar : /* forward to a class variable */
479 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
480 numKeyArgsPushed = 0;
481 selector = slotRawSymbol(&meth->selectors);
482 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
484 classobj = classOfSlot(recvrSlot);
486 goto lookup_again;
487 case methPrimitive : /* primitive */
488 doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
489 #ifdef GC_SANITYCHECK
490 g->gc->SanityCheck();
491 #endif
492 break;
495 #if TAILCALLOPTIMIZE
496 g->tailCall = 0;
497 #endif
498 #ifdef GC_SANITYCHECK
499 g->gc->SanityCheck();
500 CallStackSanity(g, "<sendSuperMessageWithKeys");
501 #endif
502 //postfl("<-sendMessage\n");
506 HOT void sendSuperMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed)
508 PyrMethod *meth = NULL;
509 PyrMethodRaw *methraw;
510 PyrSlot *recvrSlot, *sp;
511 PyrClass *classobj;
512 long index;
513 PyrObject *obj;
515 //postfl("->sendMessage\n");
516 #ifdef GC_SANITYCHECK
517 g->gc->SanityCheck();
518 CallStackSanity(g, "sendSuperMessage");
519 #endif
520 recvrSlot = g->sp - numArgsPushed + 1;
522 classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
523 //assert(isKindOfSlot(recvrSlot, classobj));
525 lookup_again:
526 index = slotRawInt(&classobj->classIndex) + selector->u.index;
527 meth = gRowTable[index];
529 if (slotRawSymbol(&meth->name) != selector) {
530 doesNotUnderstand(g, selector, numArgsPushed);
531 } else {
532 methraw = METHRAW(meth);
533 //postfl("methraw->methType %d\n", methraw->methType);
534 switch (methraw->methType) {
535 case methNormal : /* normal msg send */
536 executeMethod(g, meth, numArgsPushed);
537 break;
538 case methReturnSelf : /* return self */
539 g->sp -= numArgsPushed - 1;
540 break;
541 case methReturnLiteral : /* return literal */
542 sp = g->sp -= numArgsPushed - 1;
543 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
544 break;
545 case methReturnArg : /* return an argument */
546 sp = g->sp -= numArgsPushed - 1;
547 index = methraw->specialIndex; // zero is index of the first argument
548 if (index < numArgsPushed) {
549 slotCopy(sp, sp + index);
550 } else {
551 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
553 break;
554 case methReturnInstVar : /* return inst var */
555 sp = g->sp -= numArgsPushed - 1;
556 index = methraw->specialIndex;
557 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
558 break;
559 case methAssignInstVar : /* assign inst var */
560 sp = g->sp -= numArgsPushed - 1;
561 index = methraw->specialIndex;
562 obj = slotRawObject(recvrSlot);
563 if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); }
564 else {
565 if (numArgsPushed >= 2) {
566 slotCopy(&obj->slots[index], sp + 1);
567 g->gc->GCWrite(obj, sp + 1);
568 } else {
569 SetNil(&obj->slots[index]);
571 slotCopy(sp, recvrSlot);
573 break;
574 case methReturnClassVar : /* return class var */
575 sp = g->sp -= numArgsPushed - 1;
576 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
577 break;
578 case methAssignClassVar : /* assign class var */
579 sp = g->sp -= numArgsPushed - 1;
580 if (numArgsPushed >= 2) {
581 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
582 g->gc->GCWrite(g->classvars, sp + 1);
583 } else {
584 SetNil(&g->classvars->slots[methraw->specialIndex]);
586 slotCopy(sp, recvrSlot);
587 break;
588 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
589 if (numArgsPushed < methraw->numargs) { // not enough args pushed
590 /* push default arg values */
591 PyrSlot *pslot, *qslot;
592 long m, mmax;
593 pslot = g->sp;
594 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
595 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
596 numArgsPushed = methraw->numargs;
597 g->sp += mmax;
599 selector = slotRawSymbol(&meth->selectors);
600 goto lookup_again;
601 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
602 if (numArgsPushed < methraw->numargs) { // not enough args pushed
603 /* push default arg values */
604 PyrSlot *pslot, *qslot;
605 long m, mmax;
606 pslot = g->sp;
607 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
608 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
609 numArgsPushed = methraw->numargs;
610 g->sp += mmax;
612 selector = slotRawSymbol(&meth->selectors);
613 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
614 goto lookup_again;
615 case methForwardInstVar : /* forward to an instance variable */
616 if (numArgsPushed < methraw->numargs) { // not enough args pushed
617 /* push default arg values */
618 PyrSlot *pslot, *qslot;
619 long m, mmax;
620 pslot = g->sp;
621 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
622 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
623 numArgsPushed = methraw->numargs;
624 g->sp += mmax;
626 selector = slotRawSymbol(&meth->selectors);
627 index = methraw->specialIndex;
628 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
630 classobj = classOfSlot(recvrSlot);
632 goto lookup_again;
633 case methForwardClassVar : /* forward to a class variable */
634 if (numArgsPushed < methraw->numargs) { // not enough args pushed
635 /* push default arg values */
636 PyrSlot *pslot, *qslot;
637 long m, mmax;
638 pslot = g->sp;
639 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
640 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
641 numArgsPushed = methraw->numargs;
642 g->sp += mmax;
644 selector = slotRawSymbol(&meth->selectors);
645 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
647 classobj = classOfSlot(recvrSlot);
649 goto lookup_again;
650 case methPrimitive : /* primitive */
651 doPrimitive(g, meth, numArgsPushed);
652 #ifdef GC_SANITYCHECK
653 g->gc->SanityCheck();
654 #endif
655 break;
657 case methMultDispatchByClass : {
658 index = methraw->specialIndex;
659 if (index < numArgsPushed) {
660 classobj = slotRawObject(sp + index)->classptr;
661 selector = slotRawSymbol(&meth->selectors);
662 goto lookup_again;
663 } else {
664 doesNotUnderstand(g, selector, numArgsPushed);
666 } break;
667 case methMultDispatchByValue : {
668 index = methraw->specialIndex;
669 if (index < numArgsPushed) {
670 index = arrayAtIdentityHashInPairs(array, b);
671 meth = slotRawObject(&meth->selectors)->slots[index + 1].uom;
672 goto meth_select_again;
673 } else {
674 doesNotUnderstand(g, selector, numArgsPushed);
676 } break;
681 #if TAILCALLOPTIMIZE
682 g->tailCall = 0;
683 #endif
684 #ifdef GC_SANITYCHECK
685 g->gc->SanityCheck();
686 CallStackSanity(g, "<sendSuperMessage");
687 #endif
688 //postfl("<-sendMessage\n");
692 extern PyrClass *class_identdict;
693 void doesNotUnderstandWithKeys(VMGlobals *g, PyrSymbol *selector,
694 long numArgsPushed, long numKeyArgsPushed)
696 PyrSlot *qslot, *pslot, *pend;
697 long i, index;
698 PyrSlot *uniqueMethodSlot, *arraySlot, *recvrSlot, *selSlot, *slot;
699 PyrClass *classobj;
700 PyrMethod *meth;
701 PyrObject *array;
703 #ifdef GC_SANITYCHECK
704 g->gc->SanityCheck();
705 #endif
706 // move args up by one to make room for selector
707 qslot = g->sp + 1;
708 pslot = g->sp + 2;
709 pend = pslot - numArgsPushed + 1;
710 while (pslot > pend) *--pslot = *--qslot;
712 selSlot = g->sp - numArgsPushed + 2;
713 SetSymbol(selSlot, selector);
714 g->sp++;
716 recvrSlot = selSlot - 1;
718 classobj = classOfSlot(recvrSlot);
720 index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index;
721 meth = gRowTable[index];
724 if (slotRawClass(&meth->ownerclass) == class_object) {
725 // lookup instance specific method
726 uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods];
727 if (isKindOfSlot(uniqueMethodSlot, class_identdict)) {
728 arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array;
729 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
730 i = arrayAtIdentityHashInPairs(array, recvrSlot);
731 if (i >= 0) {
732 slot = array->slots + i;
733 if (NotNil(slot)) {
734 ++slot;
735 if (isKindOfSlot(slot, class_identdict)) {
736 arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array;
737 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
738 i = arrayAtIdentityHashInPairs(array, selSlot);
739 if (i >= 0) {
740 slot = array->slots + i;
741 if (NotNil(slot)) {
742 ++slot;
743 slotCopy(selSlot, recvrSlot);
744 slotCopy(recvrSlot, slot);
745 blockValueWithKeys(g, numArgsPushed+1, numKeyArgsPushed);
746 return;
757 executeMethodWithKeys(g, meth, numArgsPushed+1, numKeyArgsPushed);
759 #ifdef GC_SANITYCHECK
760 g->gc->SanityCheck();
761 #endif
764 int blockValue(struct VMGlobals *g, int numArgsPushed);
766 void doesNotUnderstand(VMGlobals *g, PyrSymbol *selector,
767 long numArgsPushed)
769 PyrSlot *qslot, *pslot, *pend;
770 long i, index;
771 PyrSlot *uniqueMethodSlot, *arraySlot, *recvrSlot, *selSlot, *slot;
772 PyrClass *classobj;
773 PyrMethod *meth;
774 PyrObject *array;
776 #ifdef GC_SANITYCHECK
777 g->gc->SanityCheck();
778 #endif
779 // move args up by one to make room for selector
780 qslot = g->sp + 1;
781 pslot = g->sp + 2;
782 pend = pslot - numArgsPushed + 1;
783 while (pslot > pend) *--pslot = *--qslot;
785 selSlot = g->sp - numArgsPushed + 2;
786 SetSymbol(selSlot, selector);
787 g->sp++;
789 recvrSlot = selSlot - 1;
791 classobj = classOfSlot(recvrSlot);
793 index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index;
794 meth = gRowTable[index];
797 if (slotRawClass(&meth->ownerclass) == class_object) {
798 // lookup instance specific method
799 uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods];
800 if (isKindOfSlot(uniqueMethodSlot, class_identdict)) {
801 arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array;
802 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
803 i = arrayAtIdentityHashInPairs(array, recvrSlot);
804 if (i >= 0) {
805 slot = array->slots + i;
806 if (NotNil(slot)) {
807 ++slot;
808 if (isKindOfSlot(slot, class_identdict)) {
809 arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array;
810 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
811 i = arrayAtIdentityHashInPairs(array, selSlot);
812 if (i >= 0) {
813 slot = array->slots + i;
814 if (NotNil(slot)) {
815 ++slot;
816 slotCopy(selSlot, recvrSlot);
817 slotCopy(recvrSlot, slot);
818 blockValue(g, numArgsPushed+1);
819 return;
830 executeMethod(g, meth, numArgsPushed+1);
832 #ifdef GC_SANITYCHECK
833 g->gc->SanityCheck();
834 #endif
837 HOT void executeMethodWithKeys(VMGlobals *g, PyrMethod *meth, long allArgsPushed, long numKeyArgsPushed)
839 PyrMethodRaw *methraw;
840 PyrFrame *frame;
841 PyrFrame *caller;
842 PyrSlot *pslot, *qslot;
843 PyrSlot *rslot;
844 PyrSlot *vars;
845 PyrObject *proto;
846 long i, j, m, mmax, numtemps, numargs, numArgsPushed;
848 #ifdef GC_SANITYCHECK
849 g->gc->SanityCheck();
850 CallStackSanity(g, "executeMethodWithKeys");
851 #endif
852 #if DEBUGMETHODS
853 if (gTraceInterpreter) {
854 if (g->method) {
855 postfl(" %s:%s -> %s:%s\n",
856 slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name,
857 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
858 } else {
859 postfl(" top -> %s:%s\n",
860 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
863 #endif
864 #if METHODMETER
865 if (gTraceInterpreter) {
866 slotRawInt(&meth->callMeter)++;
868 #endif
870 #if TAILCALLOPTIMIZE
871 int tailCall = g->tailCall;
872 if (tailCall) {
873 if (tailCall == 1) {
874 returnFromMethod(g);
875 } else {
876 returnFromBlock(g);
879 #endif
881 g->execMethod = 10;
883 proto = slotRawObject(&meth->prototypeFrame);
884 methraw = METHRAW(meth);
885 numtemps = methraw->numtemps;
886 numargs = methraw->numargs;
887 caller = g->frame;
888 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
889 //DumpStack(g, g->sp);
890 //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed);
892 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
893 vars = frame->vars - 1;
894 frame->classptr = class_frame;
895 frame->size = FRAMESIZE + proto->size;
896 SetObject(&frame->method, meth);
897 SetObject(&frame->homeContext, frame);
898 SetObject(&frame->context, frame);
900 if (caller) {
901 SetPtr(&caller->ip, g->ip);
902 SetObject(&frame->caller, caller);
903 } else {
904 SetInt(&frame->caller, 0);
906 SetPtr(&frame->ip, 0);
907 g->method = meth;
909 g->ip = slotRawInt8Array(&meth->code)->b - 1;
910 g->frame = frame;
911 g->block = (PyrBlock*)meth;
913 g->sp -= allArgsPushed;
914 qslot = g->sp;
915 pslot = vars;
917 if (numArgsPushed <= numargs) { /* not enough args pushed */
918 /* push all args to frame */
919 for (m=0,mmax=numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
921 /* push default arg & var values */
922 pslot = vars + numArgsPushed;
923 qslot = proto->slots + numArgsPushed - 1;
924 for (m=0, mmax=numtemps - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
925 } else if (methraw->varargs) {
926 PyrObject *list;
927 PyrSlot *lslot;
929 /* push all normal args to frame */
930 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
932 /* push list */
933 i = numArgsPushed - numargs;
934 list = newPyrArray(g->gc, i, 0, false);
935 list->size = i;
937 rslot = pslot+1;
938 SetObject(rslot, list);
939 //SetObject(vars + numargs + 1, list);
941 /* put extra args into list */
942 lslot = (list->slots - 1);
943 // fixed and raw sizes are zero
944 for (m=0,mmax=i; m<mmax; ++m) slotCopy(++lslot, ++qslot);
946 if (methraw->numvars) {
947 /* push default keyword and var values */
948 pslot = vars + numargs + 1;
949 qslot = proto->slots + numargs;
950 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
952 } else {
953 /* push all args to frame */
954 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
956 if (methraw->numvars) {
957 /* push default keyword and var values */
958 pslot = vars + numargs;
959 qslot = proto->slots + numargs - 1;
960 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
963 // do keyword lookup:
964 if (numKeyArgsPushed && methraw->posargs) {
965 PyrSymbol **name0, **name;
966 PyrSlot *key;
967 name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
968 key = g->sp + numArgsPushed + 1;
969 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
970 name = name0;
971 for (j=1; j<methraw->posargs; ++j, ++name) {
972 if (*name == slotRawSymbol(key)) {
973 slotCopy(&vars[j+1], &key[1]);
974 goto found1;
977 if (gKeywordError) {
978 post("WARNING: keyword arg '%s' not found in call to %s:%s\n",
979 slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
981 found1: ;
985 slotCopy(&g->receiver, &vars[1]);
986 #ifdef GC_SANITYCHECK
987 g->gc->SanityCheck();
988 CallStackSanity(g, "<executeMethodWithKeys");
989 #endif
993 HOT void executeMethod(VMGlobals *g, PyrMethod *meth, long numArgsPushed)
995 PyrMethodRaw *methraw;
996 PyrFrame *frame;
997 PyrFrame *caller;
998 PyrSlot *pslot, *qslot;
999 PyrSlot *rslot;
1000 PyrSlot *vars;
1001 PyrObject *proto;
1002 long i, m, mmax, numtemps, numargs;
1004 #ifdef GC_SANITYCHECK
1005 g->gc->SanityCheck();
1006 CallStackSanity(g, "executeMethod");
1007 #endif
1008 #if DEBUGMETHODS
1009 if (gTraceInterpreter) {
1010 if (g->method) {
1011 postfl(" %s:%s -> %s:%s\n",
1012 slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name,
1013 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
1014 } else {
1015 postfl(" top -> %s:%s\n",
1016 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
1019 #endif
1020 #if METHODMETER
1021 if (gTraceInterpreter) {
1022 slotRawInt(&meth->callMeter)++;
1024 #endif
1026 #if TAILCALLOPTIMIZE
1027 int tailCall = g->tailCall;
1028 if (tailCall) {
1029 if (tailCall == 1) {
1030 returnFromMethod(g);
1031 } else {
1032 returnFromBlock(g);
1035 #endif
1037 g->execMethod = 20;
1039 proto = slotRawObject(&meth->prototypeFrame);
1040 methraw = METHRAW(meth);
1041 numtemps = methraw->numtemps;
1042 numargs = methraw->numargs;
1044 caller = g->frame;
1045 //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed);
1047 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1048 vars = frame->vars - 1;
1049 frame->classptr = class_frame;
1050 frame->size = FRAMESIZE + proto->size;
1051 SetObject(&frame->method, meth);
1052 SetObject(&frame->homeContext, frame);
1053 SetObject(&frame->context, frame);
1055 if (caller) {
1056 SetPtr(&caller->ip, g->ip);
1057 SetObject(&frame->caller, caller);
1058 } else {
1059 SetInt(&frame->caller, 0);
1061 SetPtr(&frame->ip, 0);
1062 g->method = meth;
1064 g->ip = slotRawInt8Array(&meth->code)->b - 1;
1065 g->frame = frame;
1066 g->block = (PyrBlock*)meth;
1068 g->sp -= numArgsPushed;
1069 qslot = g->sp;
1070 pslot = vars;
1072 if (numArgsPushed <= numargs) { /* not enough args pushed */
1073 /* push all args to frame */
1074 for (m=0,mmax=numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1076 /* push default arg & var values */
1077 pslot = vars + numArgsPushed;
1078 qslot = proto->slots + numArgsPushed - 1;
1079 for (m=0, mmax=numtemps - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1080 } else if (methraw->varargs) {
1081 PyrObject *list;
1082 PyrSlot *lslot;
1084 /* push all normal args to frame */
1085 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1087 /* push list */
1088 i = numArgsPushed - numargs;
1089 list = newPyrArray(g->gc, i, 0, false);
1090 list->size = i;
1092 rslot = pslot+1;
1093 SetObject(rslot, list);
1094 //SetObject(vars + numargs + 1, list);
1096 /* put extra args into list */
1097 lslot = (list->slots - 1);
1098 // fixed and raw sizes are zero
1099 for (m=0,mmax=i; m<mmax; ++m) slotCopy(++lslot, ++qslot);
1101 if (methraw->numvars) {
1102 /* push default keyword and var values */
1103 pslot = vars + numargs + 1;
1104 qslot = proto->slots + numargs;
1105 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1107 } else {
1108 /* push all args to frame */
1109 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1111 if (methraw->numvars) {
1112 /* push default keyword and var values */
1113 pslot = vars + numargs;
1114 qslot = proto->slots + numargs - 1;
1115 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1118 slotCopy(&g->receiver, &vars[1]);
1120 #ifdef GC_SANITYCHECK
1121 g->gc->SanityCheck();
1122 CallStackSanity(g, "<executeMethod");
1123 #endif
1126 void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed);
1128 HOT void returnFromBlock(VMGlobals *g)
1130 PyrFrame *curframe;
1131 PyrFrame *returnFrame;
1132 PyrFrame *homeContext;
1133 PyrBlock *block;
1134 PyrMethod *meth;
1135 PyrMethodRaw *methraw;
1136 PyrMethodRaw *blockraw;
1138 //if (gTraceInterpreter) postfl("->returnFromBlock\n");
1139 //printf("->returnFromBlock\n");
1140 #ifdef GC_SANITYCHECK
1141 g->gc->SanityCheck();
1142 CallStackSanity(g, "returnFromBlock");
1143 #endif
1144 curframe = g->frame;
1146 //again:
1147 returnFrame = slotRawFrame(&curframe->caller);
1148 if (returnFrame) {
1149 block = slotRawBlock(&curframe->method);
1150 blockraw = METHRAW(block);
1152 g->frame = returnFrame;
1153 g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip);
1154 g->block = slotRawBlock(&returnFrame->method);
1155 homeContext = slotRawFrame(&returnFrame->homeContext);
1156 meth = slotRawMethod(&homeContext->method);
1157 methraw = METHRAW(meth);
1158 slotCopy(&g->receiver, &homeContext->vars[0]); //??
1159 g->method = meth;
1161 meth = slotRawMethod(&curframe->method);
1162 methraw = METHRAW(meth);
1163 if (!methraw->needsHeapContext) {
1164 g->gc->Free(curframe);
1165 } else {
1166 SetInt(&curframe->caller, 0);
1169 } else {
1170 ////// this should never happen .
1171 error("return from Function at top of call stack.\n");
1172 g->method = NULL;
1173 g->block = NULL;
1174 g->frame = NULL;
1175 g->sp = g->gc->Stack()->slots - 1;
1176 longjmp(g->escapeInterpreter, 1);
1178 //if (gTraceInterpreter) postfl("<-returnFromBlock\n");
1179 #ifdef GC_SANITYCHECK
1180 g->gc->SanityCheck();
1181 CallStackSanity(g, "returnFromBlock");
1182 #endif
1186 HOT void returnFromMethod(VMGlobals *g)
1188 PyrFrame *returnFrame, *curframe, *homeContext;
1189 PyrMethod *meth;
1190 PyrMethodRaw *methraw;
1191 curframe = g->frame;
1193 //assert(slotRawFrame(&curframe->context) == NULL);
1195 /*if (gTraceInterpreter) {
1196 post("returnFromMethod %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name);
1197 post("tailcall %d\n", g->tailCall);
1199 #ifdef GC_SANITYCHECK
1200 g->gc->SanityCheck();
1201 #endif
1202 homeContext = slotRawFrame(&slotRawFrame(&curframe->context)->homeContext);
1203 if (homeContext == NULL) {
1204 null_return:
1205 #if TAILCALLOPTIMIZE
1206 if (g->tailCall) return; // do nothing.
1207 #endif
1210 static bool once = true;
1211 if (once || gTraceInterpreter)
1213 once = false;
1214 post("return all the way out. sd %d\n", g->sp - g->gc->Stack()->slots);
1215 postfl("%s:%s\n",
1216 slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name
1218 post("tailcall %d\n", g->tailCall);
1219 post("homeContext %p\n", homeContext);
1220 post("returnFrame %p\n", returnFrame);
1221 dumpObjectSlot(&homeContext->caller);
1222 DumpStack(g, g->sp);
1223 DumpBackTrace(g);
1225 gTraceInterpreter = false;
1227 //if (IsNil(&homeContext->caller)) return; // do nothing.
1229 // return all the way out.
1230 PyrSlot *bottom = g->gc->Stack()->slots;
1231 slotCopy(bottom, g->sp);
1232 g->sp = bottom; // ??!! pop everybody
1233 g->method = NULL;
1234 g->block = NULL;
1235 g->frame = NULL;
1236 longjmp(g->escapeInterpreter, 2);
1237 } else {
1238 returnFrame = slotRawFrame(&homeContext->caller);
1240 if (returnFrame == NULL) goto null_return;
1241 // make sure returnFrame is a caller and find earliest stack frame
1243 PyrFrame *tempFrame = curframe;
1244 while (tempFrame != returnFrame) {
1245 tempFrame = slotRawFrame(&tempFrame->caller);
1246 if (!tempFrame) {
1247 if (isKindOf((PyrObject*)g->thread, class_routine) && NotNil(&g->thread->parent)) {
1248 // not found, so yield to parent thread and continue searching.
1249 PyrSlot value;
1250 slotCopy(&value, g->sp);
1252 int numArgsPushed = 1;
1253 switchToThread(g, slotRawThread(&g->thread->parent), tSuspended, &numArgsPushed);
1255 // on the other side of the looking glass, put the yielded value on the stack as the result..
1256 g->sp -= numArgsPushed - 1;
1257 slotCopy(g->sp, &value);
1259 curframe = tempFrame = g->frame;
1260 } else {
1261 slotCopy(&g->sp[2], &g->sp[0]);
1262 slotCopy(g->sp, &g->receiver);
1263 g->sp++; SetObject(g->sp, g->method);
1264 g->sp++;
1265 sendMessage(g, getsym("outOfContextReturn"), 3);
1266 return;
1273 PyrFrame *tempFrame = curframe;
1274 while (tempFrame != returnFrame) {
1275 meth = slotRawMethod(&tempFrame->method);
1276 methraw = METHRAW(meth);
1277 PyrFrame *nextFrame = slotRawFrame(&tempFrame->caller);
1278 if (!methraw->needsHeapContext) {
1279 SetInt(&tempFrame->caller, 0);
1280 } else {
1281 if (tempFrame != homeContext)
1282 SetInt(&tempFrame->caller, 0);
1284 tempFrame = nextFrame;
1288 // return to it
1289 g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip);
1290 g->frame = returnFrame;
1291 g->block = slotRawBlock(&returnFrame->method);
1293 homeContext = slotRawFrame(&returnFrame->homeContext);
1294 meth = slotRawMethod(&homeContext->method);
1295 methraw = METHRAW(meth);
1297 #if DEBUGMETHODS
1298 if (gTraceInterpreter) {
1299 postfl("%s:%s <- %s:%s\n",
1300 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name,
1301 slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name
1304 #endif
1306 g->method = meth;
1307 slotCopy(&g->receiver, &homeContext->vars[0]);
1310 #ifdef GC_SANITYCHECK
1311 g->gc->SanityCheck();
1312 #endif
1316 int keywordFixStack(VMGlobals *g, PyrMethod *meth, PyrMethodRaw *methraw, long allArgsPushed,
1317 long numKeyArgsPushed)
1319 PyrSlot *pslot, *qslot;
1320 long i, j, m, diff, numArgsPushed, numArgsNeeded;
1322 if (numKeyArgsPushed) {
1323 // evacuate keyword args to separate area
1324 pslot = keywordstack + (numKeyArgsPushed<<1);
1325 qslot = g->sp + 1;
1326 for (m=0; m<numKeyArgsPushed; ++m) {
1327 *--pslot = *--qslot;
1328 *--pslot = *--qslot;
1332 PyrSlot *vars = g->sp - allArgsPushed + 1;
1334 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
1335 numArgsNeeded = methraw->numargs;
1336 diff = numArgsNeeded - numArgsPushed;
1337 if (diff > 0) { // not enough args
1338 pslot = vars + numArgsPushed - 1;
1339 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
1340 for (m=0; m<diff; ++m) slotCopy(++pslot, ++qslot);
1341 numArgsPushed = numArgsNeeded;
1344 // do keyword lookup:
1345 if (numKeyArgsPushed && methraw->posargs) {
1346 PyrSymbol **name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
1347 PyrSlot *key = keywordstack;
1348 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
1349 PyrSymbol **name = name0;
1350 for (j=1; j<methraw->posargs; ++j, ++name) {
1351 if (*name == slotRawSymbol(key)) {
1352 slotCopy(&vars[j], &key[1]);
1353 goto found;
1356 if (gKeywordError) {
1357 post("WARNING: keyword arg '%s' not found in call to %s:%s\n",
1358 slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
1360 found: ;
1364 g->sp += numArgsPushed - allArgsPushed;
1365 return numArgsPushed;