sclang: fix returnFromMethod and returnFromBlock
[supercollider.git] / lang / LangSource / PyrMessage.cpp
blobf259c182dc574c8026d36aab6293637c03958757
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 "bullet.h"
29 #include <stdlib.h>
30 #include <assert.h>
31 #include "PredefinedSymbols.h"
32 #include "PyrObjectProto.h"
33 #include "SCBase.h"
35 #define DEBUGMETHODS 0
36 #define METHODMETER 0
38 PyrMethod **gRowTable;
40 PyrSlot keywordstack[MAXKEYSLOTS];
41 bool gKeywordError = true;
42 extern bool gTraceInterpreter;
44 long cvxUniqueMethods;
45 extern int ivxIdentDict_array;
47 void StoreToImmutableB(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip);
49 void initUniqueMethods()
51 PyrClass *dummyclass;
52 cvxUniqueMethods = classVarOffset("Object", "uniqueMethods", &dummyclass);
55 void sendMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed)
57 PyrMethod *meth = NULL;
58 PyrMethodRaw *methraw;
59 PyrSlot *recvrSlot, *sp;
60 PyrClass *classobj;
61 long index;
62 PyrObject *obj;
64 //postfl("->sendMessage\n");
65 #ifdef GC_SANITYCHECK
66 g->gc->SanityCheck();
67 CallStackSanity(g, "sendMessageWithKeys");
68 #endif
69 recvrSlot = g->sp - numArgsPushed + 1;
71 classobj = classOfSlot(recvrSlot);
73 lookup_again:
74 index = slotRawInt(&classobj->classIndex) + selector->u.index;
75 meth = gRowTable[index];
77 if (slotRawSymbol(&meth->name) != selector) {
78 doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
79 } else {
80 methraw = METHRAW(meth);
81 //postfl("methraw->methType %d\n", methraw->methType);
82 switch (methraw->methType) {
83 case methNormal : /* normal msg send */
84 executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
85 break;
86 case methReturnSelf : /* return self */
87 g->sp -= numArgsPushed - 1;
88 break;
89 case methReturnLiteral : /* return literal */
90 sp = g->sp -= numArgsPushed - 1;
91 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
92 break;
93 case methReturnArg : /* return an argument */
94 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
95 numKeyArgsPushed = 0;
96 g->sp -= numArgsPushed - 1;
97 sp = g->sp;
98 index = methraw->specialIndex; // zero is index of the first argument
99 if (index < numArgsPushed) {
100 slotCopy(sp, sp + index);
101 } else {
102 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
104 break;
105 case methReturnInstVar : /* return inst var */
106 sp = g->sp -= numArgsPushed - 1;
107 index = methraw->specialIndex;
108 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
109 break;
110 case methAssignInstVar : /* assign inst var */
111 sp = g->sp -= numArgsPushed - 1;
112 index = methraw->specialIndex;
113 obj = slotRawObject(recvrSlot);
114 if (obj->obj_flags & obj_immutable) { StoreToImmutableB(g, sp, g->ip); }
115 else {
116 if (numArgsPushed >= 2) {
117 slotCopy(&obj->slots[index], sp + 1);
118 g->gc->GCWrite(obj, sp + 1);
119 } else {
120 SetNil(&obj->slots[index]);
122 slotCopy(sp, recvrSlot);
124 break;
125 case methReturnClassVar : /* return class var */
126 sp = g->sp -= numArgsPushed - 1;
127 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
128 break;
129 case methAssignClassVar : /* assign class var */
130 sp = g->sp -= numArgsPushed - 1;
131 if (numArgsPushed >= 2) {
132 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
133 g->gc->GCWrite(g->classvars, sp + 1);
134 } else {
135 SetNil(&g->classvars->slots[methraw->specialIndex]);
137 slotCopy(sp, recvrSlot);
138 break;
139 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
140 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
141 numKeyArgsPushed = 0;
142 selector = slotRawSymbol(&meth->selectors);
143 goto lookup_again;
144 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
145 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
146 numKeyArgsPushed = 0;
147 selector = slotRawSymbol(&meth->selectors);
148 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
149 goto lookup_again;
150 case methForwardInstVar : /* forward to an instance variable */
151 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
152 numKeyArgsPushed = 0;
153 selector = slotRawSymbol(&meth->selectors);
154 index = methraw->specialIndex;
155 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
157 classobj = classOfSlot(recvrSlot);
159 goto lookup_again;
160 case methForwardClassVar : /* forward to a class variable */
161 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
162 numKeyArgsPushed = 0;
163 selector = slotRawSymbol(&meth->selectors);
164 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
166 classobj = classOfSlot(recvrSlot);
168 goto lookup_again;
169 case methPrimitive : /* primitive */
170 doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
171 #ifdef GC_SANITYCHECK
172 g->gc->SanityCheck();
173 #endif
174 break;
177 #if TAILCALLOPTIMIZE
178 g->tailCall = 0;
179 #endif
180 #ifdef GC_SANITYCHECK
181 g->gc->SanityCheck();
182 CallStackSanity(g, "<sendMessageWithKeys");
183 #endif
184 //postfl("<-sendMessage\n");
188 void sendMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed)
190 PyrMethod *meth = NULL;
191 PyrMethodRaw *methraw;
192 PyrSlot *recvrSlot, *sp;
193 PyrClass *classobj;
194 long index;
195 PyrObject *obj;
197 //postfl("->sendMessage\n");
198 #ifdef GC_SANITYCHECK
199 g->gc->SanityCheck();
200 CallStackSanity(g, "sendMessage");
201 #endif
202 recvrSlot = g->sp - numArgsPushed + 1;
204 classobj = classOfSlot(recvrSlot);
206 lookup_again:
207 index = slotRawInt(&classobj->classIndex) + selector->u.index;
208 meth = gRowTable[index];
210 if (slotRawSymbol(&meth->name) != selector) {
211 doesNotUnderstand(g, selector, numArgsPushed);
212 } else {
213 methraw = METHRAW(meth);
214 //postfl("methraw->methType %d\n", methraw->methType);
215 switch (methraw->methType) {
216 case methNormal : /* normal msg send */
217 executeMethod(g, meth, numArgsPushed);
218 break;
219 case methReturnSelf : /* return self */
220 g->sp -= numArgsPushed - 1;
221 break;
222 case methReturnLiteral : /* return literal */
223 sp = g->sp -= numArgsPushed - 1;
224 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
225 break;
226 case methReturnArg : /* return an argument */
227 sp = g->sp -= numArgsPushed - 1;
228 index = methraw->specialIndex; // zero is index of the first argument
229 if (index < numArgsPushed) {
230 slotCopy(sp, sp + index);
231 } else {
232 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
234 break;
235 case methReturnInstVar : /* return inst var */
236 sp = g->sp -= numArgsPushed - 1;
237 index = methraw->specialIndex;
238 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
239 break;
240 case methAssignInstVar : /* assign inst var */
241 sp = g->sp -= numArgsPushed - 1;
242 index = methraw->specialIndex;
243 obj = slotRawObject(recvrSlot);
244 if (obj->obj_flags & obj_immutable) { StoreToImmutableB(g, sp, g->ip); }
245 else {
246 if (numArgsPushed >= 2) {
247 slotCopy(&obj->slots[index], sp + 1);
248 g->gc->GCWrite(obj, sp + 1);
249 } else {
250 SetNil(&obj->slots[index]);
252 slotCopy(sp, recvrSlot);
254 break;
255 case methReturnClassVar : /* return class var */
256 sp = g->sp -= numArgsPushed - 1;
257 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
258 break;
259 case methAssignClassVar : /* assign class var */
260 sp = g->sp -= numArgsPushed - 1;
261 if (numArgsPushed >= 2) {
262 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
263 g->gc->GCWrite(g->classvars, sp + 1);
264 } else {
265 SetNil(&g->classvars->slots[methraw->specialIndex]);
267 slotCopy(sp, recvrSlot);
268 break;
269 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
270 if (numArgsPushed < methraw->numargs) { // not enough args pushed
271 /* push default arg values */
272 PyrSlot *pslot, *qslot;
273 long m, mmax;
274 pslot = g->sp;
275 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
276 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
277 numArgsPushed = methraw->numargs;
278 g->sp += mmax;
280 selector = slotRawSymbol(&meth->selectors);
281 goto lookup_again;
282 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
283 if (numArgsPushed < methraw->numargs) { // not enough args pushed
284 /* push default arg values */
285 PyrSlot *pslot, *qslot;
286 long m, mmax;
287 pslot = g->sp;
288 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
289 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
290 numArgsPushed = methraw->numargs;
291 g->sp += mmax;
293 selector = slotRawSymbol(&meth->selectors);
294 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
295 goto lookup_again;
296 case methForwardInstVar : /* forward to an instance variable */
297 if (numArgsPushed < methraw->numargs) { // not enough args pushed
298 /* push default arg values */
299 PyrSlot *pslot, *qslot;
300 long m, mmax;
301 pslot = g->sp;
302 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
303 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
304 numArgsPushed = methraw->numargs;
305 g->sp += mmax;
307 selector = slotRawSymbol(&meth->selectors);
308 index = methraw->specialIndex;
309 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
311 classobj = classOfSlot(recvrSlot);
313 goto lookup_again;
314 case methForwardClassVar : /* forward to a class variable */
315 if (numArgsPushed < methraw->numargs) { // not enough args pushed
316 /* push default arg values */
317 PyrSlot *pslot, *qslot;
318 long m, mmax;
319 pslot = g->sp;
320 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
321 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
322 numArgsPushed = methraw->numargs;
323 g->sp += mmax;
325 selector = slotRawSymbol(&meth->selectors);
326 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
328 classobj = classOfSlot(recvrSlot);
330 goto lookup_again;
331 case methPrimitive : /* primitive */
332 doPrimitive(g, meth, numArgsPushed);
333 #ifdef GC_SANITYCHECK
334 g->gc->SanityCheck();
335 #endif
336 break;
338 case methMultDispatchByClass : {
339 index = methraw->specialIndex;
340 if (index < numArgsPushed) {
341 classobj = slotRawObject(sp + index)->classptr;
342 selector = slotRawSymbol(&meth->selectors);
343 goto lookup_again;
344 } else {
345 doesNotUnderstand(g, selector, numArgsPushed);
347 } break;
348 case methMultDispatchByValue : {
349 index = methraw->specialIndex;
350 if (index < numArgsPushed) {
351 index = arrayAtIdentityHashInPairs(array, b);
352 meth = slotRawObject(&meth->selectors)->slots[index + 1].uom;
353 goto meth_select_again;
354 } else {
355 doesNotUnderstand(g, selector, numArgsPushed);
357 } break;
362 #if TAILCALLOPTIMIZE
363 g->tailCall = 0;
364 #endif
365 #ifdef GC_SANITYCHECK
366 g->gc->SanityCheck();
367 CallStackSanity(g, "<sendMessage");
368 #endif
369 //postfl("<-sendMessage\n");
373 void sendSuperMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed)
375 PyrMethod *meth = NULL;
376 PyrMethodRaw *methraw;
377 PyrSlot *recvrSlot, *sp;
378 PyrClass *classobj;
379 long index;
380 PyrObject *obj;
382 //postfl("->sendMessage\n");
383 #ifdef GC_SANITYCHECK
384 g->gc->SanityCheck();
385 CallStackSanity(g, "sendSuperMessageWithKeys");
386 #endif
387 recvrSlot = g->sp - numArgsPushed + 1;
389 classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
390 //assert(isKindOfSlot(recvrSlot, classobj));
392 lookup_again:
393 index = slotRawInt(&classobj->classIndex) + selector->u.index;
394 meth = gRowTable[index];
396 if (slotRawSymbol(&meth->name) != selector) {
397 doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
398 } else {
399 methraw = METHRAW(meth);
400 //postfl("methraw->methType %d\n", methraw->methType);
401 switch (methraw->methType) {
402 case methNormal : /* normal msg send */
403 executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
404 break;
405 case methReturnSelf : /* return self */
406 g->sp -= numArgsPushed - 1;
407 break;
408 case methReturnLiteral : /* return literal */
409 sp = g->sp -= numArgsPushed - 1;
410 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
411 break;
412 case methReturnArg : /* return an argument */
413 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
414 numKeyArgsPushed = 0;
415 g->sp -= numArgsPushed - 1;
416 sp = g->sp;
417 index = methraw->specialIndex; // zero is index of the first argument
418 if (index < numArgsPushed) {
419 slotCopy(sp, sp + index);
420 } else {
421 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
423 break;
424 case methReturnInstVar : /* return inst var */
425 sp = g->sp -= numArgsPushed - 1;
426 index = methraw->specialIndex;
427 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
428 break;
429 case methAssignInstVar : /* assign inst var */
430 sp = g->sp -= numArgsPushed - 1;
431 index = methraw->specialIndex;
432 obj = slotRawObject(recvrSlot);
433 if (obj->obj_flags & obj_immutable) { StoreToImmutableB(g, sp, g->ip); }
434 else {
435 if (numArgsPushed >= 2) {
436 slotCopy(&obj->slots[index], sp + 1);
437 g->gc->GCWrite(obj, sp + 1);
438 } else {
439 SetNil(&obj->slots[index]);
441 slotCopy(sp, recvrSlot);
443 break;
444 case methReturnClassVar : /* return class var */
445 sp = g->sp -= numArgsPushed - 1;
446 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
447 break;
448 case methAssignClassVar : /* assign class var */
449 sp = g->sp -= numArgsPushed - 1;
450 if (numArgsPushed >= 2) {
451 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
452 g->gc->GCWrite(g->classvars, sp + 1);
453 } else {
454 SetNil(&g->classvars->slots[methraw->specialIndex]);
456 slotCopy(sp, recvrSlot);
457 break;
458 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
459 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
460 numKeyArgsPushed = 0;
461 selector = slotRawSymbol(&meth->selectors);
462 goto lookup_again;
463 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
464 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
465 numKeyArgsPushed = 0;
466 selector = slotRawSymbol(&meth->selectors);
467 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
468 goto lookup_again;
469 case methForwardInstVar : /* forward to an instance variable */
470 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
471 numKeyArgsPushed = 0;
472 selector = slotRawSymbol(&meth->selectors);
473 index = methraw->specialIndex;
474 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
476 classobj = classOfSlot(recvrSlot);
478 goto lookup_again;
479 case methForwardClassVar : /* forward to a class variable */
480 numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed);
481 numKeyArgsPushed = 0;
482 selector = slotRawSymbol(&meth->selectors);
483 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
485 classobj = classOfSlot(recvrSlot);
487 goto lookup_again;
488 case methPrimitive : /* primitive */
489 doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed);
490 #ifdef GC_SANITYCHECK
491 g->gc->SanityCheck();
492 #endif
493 break;
496 #if TAILCALLOPTIMIZE
497 g->tailCall = 0;
498 #endif
499 #ifdef GC_SANITYCHECK
500 g->gc->SanityCheck();
501 CallStackSanity(g, "<sendSuperMessageWithKeys");
502 #endif
503 //postfl("<-sendMessage\n");
507 void sendSuperMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed)
509 PyrMethod *meth = NULL;
510 PyrMethodRaw *methraw;
511 PyrSlot *recvrSlot, *sp;
512 PyrClass *classobj;
513 long index;
514 PyrObject *obj;
516 //postfl("->sendMessage\n");
517 #ifdef GC_SANITYCHECK
518 g->gc->SanityCheck();
519 CallStackSanity(g, "sendSuperMessage");
520 #endif
521 recvrSlot = g->sp - numArgsPushed + 1;
523 classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
524 //assert(isKindOfSlot(recvrSlot, classobj));
526 lookup_again:
527 index = slotRawInt(&classobj->classIndex) + selector->u.index;
528 meth = gRowTable[index];
530 if (slotRawSymbol(&meth->name) != selector) {
531 doesNotUnderstand(g, selector, numArgsPushed);
532 } else {
533 methraw = METHRAW(meth);
534 //postfl("methraw->methType %d\n", methraw->methType);
535 switch (methraw->methType) {
536 case methNormal : /* normal msg send */
537 executeMethod(g, meth, numArgsPushed);
538 break;
539 case methReturnSelf : /* return self */
540 g->sp -= numArgsPushed - 1;
541 break;
542 case methReturnLiteral : /* return literal */
543 sp = g->sp -= numArgsPushed - 1;
544 slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */
545 break;
546 case methReturnArg : /* return an argument */
547 sp = g->sp -= numArgsPushed - 1;
548 index = methraw->specialIndex; // zero is index of the first argument
549 if (index < numArgsPushed) {
550 slotCopy(sp, sp + index);
551 } else {
552 slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]);
554 break;
555 case methReturnInstVar : /* return inst var */
556 sp = g->sp -= numArgsPushed - 1;
557 index = methraw->specialIndex;
558 slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]);
559 break;
560 case methAssignInstVar : /* assign inst var */
561 sp = g->sp -= numArgsPushed - 1;
562 index = methraw->specialIndex;
563 obj = slotRawObject(recvrSlot);
564 if (obj->obj_flags & obj_immutable) { StoreToImmutableB(g, sp, g->ip); }
565 else {
566 if (numArgsPushed >= 2) {
567 slotCopy(&obj->slots[index], sp + 1);
568 g->gc->GCWrite(obj, sp + 1);
569 } else {
570 SetNil(&obj->slots[index]);
572 slotCopy(sp, recvrSlot);
574 break;
575 case methReturnClassVar : /* return class var */
576 sp = g->sp -= numArgsPushed - 1;
577 slotCopy(sp, &g->classvars->slots[methraw->specialIndex]);
578 break;
579 case methAssignClassVar : /* assign class var */
580 sp = g->sp -= numArgsPushed - 1;
581 if (numArgsPushed >= 2) {
582 slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1);
583 g->gc->GCWrite(g->classvars, sp + 1);
584 } else {
585 SetNil(&g->classvars->slots[methraw->specialIndex]);
587 slotCopy(sp, recvrSlot);
588 break;
589 case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */
590 if (numArgsPushed < methraw->numargs) { // not enough args pushed
591 /* push default arg values */
592 PyrSlot *pslot, *qslot;
593 long m, mmax;
594 pslot = g->sp;
595 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
596 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
597 numArgsPushed = methraw->numargs;
598 g->sp += mmax;
600 selector = slotRawSymbol(&meth->selectors);
601 goto lookup_again;
602 case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */
603 if (numArgsPushed < methraw->numargs) { // not enough args pushed
604 /* push default arg values */
605 PyrSlot *pslot, *qslot;
606 long m, mmax;
607 pslot = g->sp;
608 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
609 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
610 numArgsPushed = methraw->numargs;
611 g->sp += mmax;
613 selector = slotRawSymbol(&meth->selectors);
614 classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj;
615 goto lookup_again;
616 case methForwardInstVar : /* forward to an instance variable */
617 if (numArgsPushed < methraw->numargs) { // not enough args pushed
618 /* push default arg values */
619 PyrSlot *pslot, *qslot;
620 long m, mmax;
621 pslot = g->sp;
622 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
623 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
624 numArgsPushed = methraw->numargs;
625 g->sp += mmax;
627 selector = slotRawSymbol(&meth->selectors);
628 index = methraw->specialIndex;
629 slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]);
631 classobj = classOfSlot(recvrSlot);
633 goto lookup_again;
634 case methForwardClassVar : /* forward to a class variable */
635 if (numArgsPushed < methraw->numargs) { // not enough args pushed
636 /* push default arg values */
637 PyrSlot *pslot, *qslot;
638 long m, mmax;
639 pslot = g->sp;
640 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
641 for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
642 numArgsPushed = methraw->numargs;
643 g->sp += mmax;
645 selector = slotRawSymbol(&meth->selectors);
646 slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]);
648 classobj = classOfSlot(recvrSlot);
650 goto lookup_again;
651 case methPrimitive : /* primitive */
652 doPrimitive(g, meth, numArgsPushed);
653 #ifdef GC_SANITYCHECK
654 g->gc->SanityCheck();
655 #endif
656 break;
658 case methMultDispatchByClass : {
659 index = methraw->specialIndex;
660 if (index < numArgsPushed) {
661 classobj = slotRawObject(sp + index)->classptr;
662 selector = slotRawSymbol(&meth->selectors);
663 goto lookup_again;
664 } else {
665 doesNotUnderstand(g, selector, numArgsPushed);
667 } break;
668 case methMultDispatchByValue : {
669 index = methraw->specialIndex;
670 if (index < numArgsPushed) {
671 index = arrayAtIdentityHashInPairs(array, b);
672 meth = slotRawObject(&meth->selectors)->slots[index + 1].uom;
673 goto meth_select_again;
674 } else {
675 doesNotUnderstand(g, selector, numArgsPushed);
677 } break;
682 #if TAILCALLOPTIMIZE
683 g->tailCall = 0;
684 #endif
685 #ifdef GC_SANITYCHECK
686 g->gc->SanityCheck();
687 CallStackSanity(g, "<sendSuperMessage");
688 #endif
689 //postfl("<-sendMessage\n");
693 extern PyrClass *class_identdict;
694 void doesNotUnderstandWithKeys(VMGlobals *g, PyrSymbol *selector,
695 long numArgsPushed, long numKeyArgsPushed)
697 PyrSlot *qslot, *pslot, *pend;
698 long i, index;
699 PyrSlot *uniqueMethodSlot, *arraySlot, *recvrSlot, *selSlot, *slot;
700 PyrClass *classobj;
701 PyrMethod *meth;
702 PyrObject *array;
704 #ifdef GC_SANITYCHECK
705 g->gc->SanityCheck();
706 #endif
707 // move args up by one to make room for selector
708 qslot = g->sp + 1;
709 pslot = g->sp + 2;
710 pend = pslot - numArgsPushed + 1;
711 while (pslot > pend) *--pslot = *--qslot;
713 selSlot = g->sp - numArgsPushed + 2;
714 SetSymbol(selSlot, selector);
715 g->sp++;
717 recvrSlot = selSlot - 1;
719 classobj = classOfSlot(recvrSlot);
721 index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index;
722 meth = gRowTable[index];
725 if (slotRawClass(&meth->ownerclass) == class_object) {
726 // lookup instance specific method
727 uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods];
728 if (isKindOfSlot(uniqueMethodSlot, class_identdict)) {
729 arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array;
730 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
731 i = arrayAtIdentityHashInPairs(array, recvrSlot);
732 if (i >= 0) {
733 slot = array->slots + i;
734 if (NotNil(slot)) {
735 ++slot;
736 if (isKindOfSlot(slot, class_identdict)) {
737 arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array;
738 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
739 i = arrayAtIdentityHashInPairs(array, selSlot);
740 if (i >= 0) {
741 slot = array->slots + i;
742 if (NotNil(slot)) {
743 ++slot;
744 slotCopy(selSlot, recvrSlot);
745 slotCopy(recvrSlot, slot);
746 blockValueWithKeys(g, numArgsPushed+1, numKeyArgsPushed);
747 return;
758 executeMethodWithKeys(g, meth, numArgsPushed+1, numKeyArgsPushed);
760 #ifdef GC_SANITYCHECK
761 g->gc->SanityCheck();
762 #endif
765 int blockValue(struct VMGlobals *g, int numArgsPushed);
767 void doesNotUnderstand(VMGlobals *g, PyrSymbol *selector,
768 long numArgsPushed)
770 PyrSlot *qslot, *pslot, *pend;
771 long i, index;
772 PyrSlot *uniqueMethodSlot, *arraySlot, *recvrSlot, *selSlot, *slot;
773 PyrClass *classobj;
774 PyrMethod *meth;
775 PyrObject *array;
777 #ifdef GC_SANITYCHECK
778 g->gc->SanityCheck();
779 #endif
780 // move args up by one to make room for selector
781 qslot = g->sp + 1;
782 pslot = g->sp + 2;
783 pend = pslot - numArgsPushed + 1;
784 while (pslot > pend) *--pslot = *--qslot;
786 selSlot = g->sp - numArgsPushed + 2;
787 SetSymbol(selSlot, selector);
788 g->sp++;
790 recvrSlot = selSlot - 1;
792 classobj = classOfSlot(recvrSlot);
794 index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index;
795 meth = gRowTable[index];
798 if (slotRawClass(&meth->ownerclass) == class_object) {
799 // lookup instance specific method
800 uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods];
801 if (isKindOfSlot(uniqueMethodSlot, class_identdict)) {
802 arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array;
803 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
804 i = arrayAtIdentityHashInPairs(array, recvrSlot);
805 if (i >= 0) {
806 slot = array->slots + i;
807 if (NotNil(slot)) {
808 ++slot;
809 if (isKindOfSlot(slot, class_identdict)) {
810 arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array;
811 if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) {
812 i = arrayAtIdentityHashInPairs(array, selSlot);
813 if (i >= 0) {
814 slot = array->slots + i;
815 if (NotNil(slot)) {
816 ++slot;
817 slotCopy(selSlot, recvrSlot);
818 slotCopy(recvrSlot, slot);
819 blockValue(g, numArgsPushed+1);
820 return;
831 executeMethod(g, meth, numArgsPushed+1);
833 #ifdef GC_SANITYCHECK
834 g->gc->SanityCheck();
835 #endif
838 void executeMethodWithKeys(VMGlobals *g, PyrMethod *meth, long allArgsPushed, long numKeyArgsPushed)
840 PyrMethodRaw *methraw;
841 PyrFrame *frame;
842 PyrFrame *caller;
843 PyrSlot *pslot, *qslot;
844 PyrSlot *rslot;
845 PyrSlot *vars;
846 PyrObject *proto;
847 long i, j, m, mmax, numtemps, numargs, numArgsPushed;
849 #ifdef GC_SANITYCHECK
850 g->gc->SanityCheck();
851 CallStackSanity(g, "executeMethodWithKeys");
852 #endif
853 #if DEBUGMETHODS
854 if (gTraceInterpreter) {
855 if (g->method) {
856 postfl(" %s:%s -> %s:%s\n",
857 slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name,
858 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
859 } else {
860 postfl(" top -> %s:%s\n",
861 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
864 #endif
865 #if METHODMETER
866 if (gTraceInterpreter) {
867 slotRawInt(&meth->callMeter)++;
869 #endif
871 #if TAILCALLOPTIMIZE
872 int tailCall = g->tailCall;
873 if (tailCall) {
874 if (tailCall == 1) {
875 returnFromMethod(g);
876 } else {
877 returnFromBlock(g);
880 #endif
882 g->execMethod = 10;
884 proto = slotRawObject(&meth->prototypeFrame);
885 methraw = METHRAW(meth);
886 numtemps = methraw->numtemps;
887 numargs = methraw->numargs;
888 caller = g->frame;
889 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
890 //DumpStack(g, g->sp);
891 //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed);
893 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
894 vars = frame->vars - 1;
895 frame->classptr = class_frame;
896 frame->size = FRAMESIZE + proto->size;
897 SetObject(&frame->method, meth);
898 SetObject(&frame->homeContext, frame);
899 SetObject(&frame->context, frame);
901 if (caller) {
902 SetPtr(&caller->ip, g->ip);
903 SetObject(&frame->caller, caller);
904 } else {
905 SetInt(&frame->caller, 0);
907 SetPtr(&frame->ip, 0);
908 g->method = meth;
910 g->ip = slotRawInt8Array(&meth->code)->b - 1;
911 g->frame = frame;
912 g->block = (PyrBlock*)meth;
914 g->sp -= allArgsPushed;
915 qslot = g->sp;
916 pslot = vars;
918 if (numArgsPushed <= numargs) { /* not enough args pushed */
919 /* push all args to frame */
920 for (m=0,mmax=numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
922 /* push default arg & var values */
923 pslot = vars + numArgsPushed;
924 qslot = proto->slots + numArgsPushed - 1;
925 for (m=0, mmax=numtemps - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
926 } else if (methraw->varargs) {
927 PyrObject *list;
928 PyrSlot *lslot;
930 /* push all normal args to frame */
931 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
933 /* push list */
934 i = numArgsPushed - numargs;
935 list = newPyrArray(g->gc, i, 0, false);
936 list->size = i;
938 rslot = pslot+1;
939 SetObject(rslot, list);
940 //SetObject(vars + numargs + 1, list);
942 /* put extra args into list */
943 lslot = (list->slots - 1);
944 // fixed and raw sizes are zero
945 for (m=0,mmax=i; m<mmax; ++m) slotCopy(++lslot, ++qslot);
947 if (methraw->numvars) {
948 /* push default keyword and var values */
949 pslot = vars + numargs + 1;
950 qslot = proto->slots + numargs;
951 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
953 } else {
954 /* push all args to frame */
955 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
957 if (methraw->numvars) {
958 /* push default keyword and var values */
959 pslot = vars + numargs;
960 qslot = proto->slots + numargs - 1;
961 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
964 // do keyword lookup:
965 if (numKeyArgsPushed && methraw->posargs) {
966 PyrSymbol **name0, **name;
967 PyrSlot *key;
968 name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
969 key = g->sp + numArgsPushed + 1;
970 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
971 name = name0;
972 for (j=1; j<methraw->posargs; ++j, ++name) {
973 if (*name == slotRawSymbol(key)) {
974 slotCopy(&vars[j+1], &key[1]);
975 goto found1;
978 if (gKeywordError) {
979 post("WARNING: keyword arg '%s' not found in call to %s:%s\n",
980 slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
982 found1: ;
986 slotCopy(&g->receiver, &vars[1]);
987 #ifdef GC_SANITYCHECK
988 g->gc->SanityCheck();
989 CallStackSanity(g, "<executeMethodWithKeys");
990 #endif
994 void executeMethod(VMGlobals *g, PyrMethod *meth, long numArgsPushed)
996 PyrMethodRaw *methraw;
997 PyrFrame *frame;
998 PyrFrame *caller;
999 PyrSlot *pslot, *qslot;
1000 PyrSlot *rslot;
1001 PyrSlot *vars;
1002 PyrObject *proto;
1003 long i, m, mmax, numtemps, numargs;
1005 #ifdef GC_SANITYCHECK
1006 g->gc->SanityCheck();
1007 CallStackSanity(g, "executeMethod");
1008 #endif
1009 #if DEBUGMETHODS
1010 if (gTraceInterpreter) {
1011 if (g->method) {
1012 postfl(" %s:%s -> %s:%s\n",
1013 slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name,
1014 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
1015 } else {
1016 postfl(" top -> %s:%s\n",
1017 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
1020 #endif
1021 #if METHODMETER
1022 if (gTraceInterpreter) {
1023 slotRawInt(&meth->callMeter)++;
1025 #endif
1027 #if TAILCALLOPTIMIZE
1028 int tailCall = g->tailCall;
1029 if (tailCall) {
1030 if (tailCall == 1) {
1031 returnFromMethod(g);
1032 } else {
1033 returnFromBlock(g);
1036 #endif
1038 g->execMethod = 20;
1040 proto = slotRawObject(&meth->prototypeFrame);
1041 methraw = METHRAW(meth);
1042 numtemps = methraw->numtemps;
1043 numargs = methraw->numargs;
1045 caller = g->frame;
1046 //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed);
1048 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1049 vars = frame->vars - 1;
1050 frame->classptr = class_frame;
1051 frame->size = FRAMESIZE + proto->size;
1052 SetObject(&frame->method, meth);
1053 SetObject(&frame->homeContext, frame);
1054 SetObject(&frame->context, frame);
1056 if (caller) {
1057 SetPtr(&caller->ip, g->ip);
1058 SetObject(&frame->caller, caller);
1059 } else {
1060 SetInt(&frame->caller, 0);
1062 SetPtr(&frame->ip, 0);
1063 g->method = meth;
1065 g->ip = slotRawInt8Array(&meth->code)->b - 1;
1066 g->frame = frame;
1067 g->block = (PyrBlock*)meth;
1069 g->sp -= numArgsPushed;
1070 qslot = g->sp;
1071 pslot = vars;
1073 if (numArgsPushed <= numargs) { /* not enough args pushed */
1074 /* push all args to frame */
1075 for (m=0,mmax=numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1077 /* push default arg & var values */
1078 pslot = vars + numArgsPushed;
1079 qslot = proto->slots + numArgsPushed - 1;
1080 for (m=0, mmax=numtemps - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1081 } else if (methraw->varargs) {
1082 PyrObject *list;
1083 PyrSlot *lslot;
1085 /* push all normal args to frame */
1086 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1088 /* push list */
1089 i = numArgsPushed - numargs;
1090 list = newPyrArray(g->gc, i, 0, false);
1091 list->size = i;
1093 rslot = pslot+1;
1094 SetObject(rslot, list);
1095 //SetObject(vars + numargs + 1, list);
1097 /* put extra args into list */
1098 lslot = (list->slots - 1);
1099 // fixed and raw sizes are zero
1100 for (m=0,mmax=i; m<mmax; ++m) slotCopy(++lslot, ++qslot);
1102 if (methraw->numvars) {
1103 /* push default keyword and var values */
1104 pslot = vars + numargs + 1;
1105 qslot = proto->slots + numargs;
1106 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1108 } else {
1109 /* push all args to frame */
1110 for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1112 if (methraw->numvars) {
1113 /* push default keyword and var values */
1114 pslot = vars + numargs;
1115 qslot = proto->slots + numargs - 1;
1116 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1119 slotCopy(&g->receiver, &vars[1]);
1121 #ifdef GC_SANITYCHECK
1122 g->gc->SanityCheck();
1123 CallStackSanity(g, "<executeMethod");
1124 #endif
1127 void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed);
1129 void returnFromBlock(VMGlobals *g)
1131 PyrFrame *curframe;
1132 PyrFrame *returnFrame;
1133 PyrFrame *homeContext;
1134 PyrBlock *block;
1135 PyrMethod *meth;
1136 PyrMethodRaw *methraw;
1137 PyrMethodRaw *blockraw;
1139 //if (gTraceInterpreter) postfl("->returnFromBlock\n");
1140 //printf("->returnFromBlock\n");
1141 #ifdef GC_SANITYCHECK
1142 g->gc->SanityCheck();
1143 CallStackSanity(g, "returnFromBlock");
1144 #endif
1145 curframe = g->frame;
1147 //again:
1148 returnFrame = slotRawFrame(&curframe->caller);
1149 if (returnFrame) {
1150 block = slotRawBlock(&curframe->method);
1151 blockraw = METHRAW(block);
1153 g->frame = returnFrame;
1154 g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip);
1155 g->block = slotRawBlock(&returnFrame->method);
1156 homeContext = slotRawFrame(&returnFrame->homeContext);
1157 meth = slotRawMethod(&homeContext->method);
1158 methraw = METHRAW(meth);
1159 slotCopy(&g->receiver, &homeContext->vars[0]); //??
1160 g->method = meth;
1162 meth = slotRawMethod(&curframe->method);
1163 methraw = METHRAW(meth);
1164 if (!methraw->needsHeapContext) {
1165 g->gc->Free(curframe);
1166 } else {
1167 SetInt(&curframe->caller, 0);
1170 } else {
1171 ////// this should never happen .
1172 error("return from Function at top of call stack.\n");
1173 g->method = NULL;
1174 g->block = NULL;
1175 g->frame = NULL;
1176 g->sp = g->gc->Stack()->slots - 1;
1177 longjmp(g->escapeInterpreter, 1);
1179 //if (gTraceInterpreter) postfl("<-returnFromBlock\n");
1180 #ifdef GC_SANITYCHECK
1181 g->gc->SanityCheck();
1182 CallStackSanity(g, "returnFromBlock");
1183 #endif
1187 void returnFromMethod(VMGlobals *g)
1189 PyrFrame *returnFrame, *curframe, *homeContext;
1190 PyrMethod *meth;
1191 PyrMethodRaw *methraw;
1192 curframe = g->frame;
1194 //assert(slotRawFrame(&curframe->context) == NULL);
1196 /*if (gTraceInterpreter) {
1197 post("returnFromMethod %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name);
1198 post("tailcall %d\n", g->tailCall);
1200 #ifdef GC_SANITYCHECK
1201 g->gc->SanityCheck();
1202 #endif
1203 homeContext = slotRawFrame(&slotRawFrame(&curframe->context)->homeContext);
1204 if (homeContext == NULL) {
1205 null_return:
1206 #if TAILCALLOPTIMIZE
1207 if (g->tailCall) return; // do nothing.
1208 #endif
1211 static bool once = true;
1212 if (once || gTraceInterpreter)
1214 once = false;
1215 post("return all the way out. sd %d\n", g->sp - g->gc->Stack()->slots);
1216 postfl("%s:%s\n",
1217 slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name
1219 post("tailcall %d\n", g->tailCall);
1220 post("homeContext %p\n", homeContext);
1221 post("returnFrame %p\n", returnFrame);
1222 dumpObjectSlot(&homeContext->caller);
1223 DumpStack(g, g->sp);
1224 DumpBackTrace(g);
1226 gTraceInterpreter = false;
1228 //if (IsNil(&homeContext->caller)) return; // do nothing.
1230 // return all the way out.
1231 PyrSlot *bottom = g->gc->Stack()->slots;
1232 slotCopy(bottom, g->sp);
1233 g->sp = bottom; // ??!! pop everybody
1234 g->method = NULL;
1235 g->block = NULL;
1236 g->frame = NULL;
1237 longjmp(g->escapeInterpreter, 2);
1238 } else {
1239 returnFrame = slotRawFrame(&homeContext->caller);
1241 if (returnFrame == NULL) goto null_return;
1242 // make sure returnFrame is a caller and find earliest stack frame
1244 PyrFrame *tempFrame = curframe;
1245 while (tempFrame != returnFrame) {
1246 tempFrame = slotRawFrame(&tempFrame->caller);
1247 if (!tempFrame) {
1248 if (isKindOf((PyrObject*)g->thread, class_routine) && NotNil(&g->thread->parent)) {
1249 // not found, so yield to parent thread and continue searching.
1250 PyrSlot value;
1251 slotCopy(&value, g->sp);
1253 int numArgsPushed = 1;
1254 switchToThread(g, slotRawThread(&g->thread->parent), tSuspended, &numArgsPushed);
1256 // on the other side of the looking glass, put the yielded value on the stack as the result..
1257 g->sp -= numArgsPushed - 1;
1258 slotCopy(g->sp, &value);
1260 curframe = tempFrame = g->frame;
1261 } else {
1262 slotCopy(&g->sp[2], &g->sp[0]);
1263 slotCopy(g->sp, &g->receiver);
1264 g->sp++; SetObject(g->sp, g->method);
1265 g->sp++;
1266 sendMessage(g, getsym("outOfContextReturn"), 3);
1267 return;
1274 PyrFrame *tempFrame = curframe;
1275 while (tempFrame != returnFrame) {
1276 meth = slotRawMethod(&tempFrame->method);
1277 methraw = METHRAW(meth);
1278 PyrFrame *nextFrame = slotRawFrame(&tempFrame->caller);
1279 if (!methraw->needsHeapContext) {
1280 SetInt(&tempFrame->caller, 0);
1281 } else {
1282 if (tempFrame != homeContext)
1283 SetInt(&tempFrame->caller, 0);
1285 tempFrame = nextFrame;
1289 // return to it
1290 g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip);
1291 g->frame = returnFrame;
1292 g->block = slotRawBlock(&returnFrame->method);
1294 homeContext = slotRawFrame(&returnFrame->homeContext);
1295 meth = slotRawMethod(&homeContext->method);
1296 methraw = METHRAW(meth);
1298 #if DEBUGMETHODS
1299 if (gTraceInterpreter) {
1300 postfl("%s:%s <- %s:%s\n",
1301 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name,
1302 slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name
1305 #endif
1307 g->method = meth;
1308 slotCopy(&g->receiver, &homeContext->vars[0]);
1311 #ifdef GC_SANITYCHECK
1312 g->gc->SanityCheck();
1313 #endif
1317 int keywordFixStack(VMGlobals *g, PyrMethod *meth, PyrMethodRaw *methraw, long allArgsPushed,
1318 long numKeyArgsPushed)
1320 PyrSlot *pslot, *qslot;
1321 long i, j, m, diff, numArgsPushed, numArgsNeeded;
1323 if (numKeyArgsPushed) {
1324 // evacuate keyword args to separate area
1325 pslot = keywordstack + (numKeyArgsPushed<<1);
1326 qslot = g->sp + 1;
1327 for (m=0; m<numKeyArgsPushed; ++m) {
1328 *--pslot = *--qslot;
1329 *--pslot = *--qslot;
1333 PyrSlot *vars = g->sp - allArgsPushed + 1;
1335 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
1336 numArgsNeeded = methraw->numargs;
1337 diff = numArgsNeeded - numArgsPushed;
1338 if (diff > 0) { // not enough args
1339 pslot = vars + numArgsPushed - 1;
1340 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
1341 for (m=0; m<diff; ++m) slotCopy(++pslot, ++qslot);
1342 numArgsPushed = numArgsNeeded;
1345 // do keyword lookup:
1346 if (numKeyArgsPushed && methraw->posargs) {
1347 PyrSymbol **name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
1348 PyrSlot *key = keywordstack;
1349 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
1350 PyrSymbol **name = name0;
1351 for (j=1; j<methraw->posargs; ++j, ++name) {
1352 if (*name == slotRawSymbol(key)) {
1353 slotCopy(&vars[j], &key[1]);
1354 goto found;
1357 if (gKeywordError) {
1358 post("WARNING: keyword arg '%s' not found in call to %s:%s\n",
1359 slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
1361 found: ;
1365 g->sp += numArgsPushed - allArgsPushed;
1366 return numArgsPushed;