HOT void returnFromBlock(VMGlobals *g) { PyrFrame *curframe; PyrFrame *returnFrame; PyrFrame *homeContext; PyrBlock *block; PyrMethod *meth; PyrMethodRaw *methraw; PyrMethodRaw *blockraw; //if (gTraceInterpreter) postfl("->returnFromBlock\n"); //printf("->returnFromBlock\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock"); #endif curframe = g->frame; //again: returnFrame = slotRawFrame(&curframe->caller); if (returnFrame) { block = slotRawBlock(&curframe->method); blockraw = METHRAW(block); g->frame = returnFrame; g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip); g->block = slotRawBlock(&returnFrame->method); homeContext = slotRawFrame(&returnFrame->homeContext); meth = slotRawMethod(&homeContext->method); methraw = METHRAW(meth); slotCopy(&g->receiver, &homeContext->vars[0]); //?? g->method = meth; meth = slotRawMethod(&curframe->method); methraw = METHRAW(meth); if (!methraw->needsHeapContext) { g->gc->Free(curframe); } else { SetInt(&curframe->caller, 0); } } else { ////// this should never happen . error("return from Function at top of call stack.\n"); g->method = NULL; g->block = NULL; g->frame = NULL; g->sp = g->gc->Stack()->slots - 1; longjmp(g->escapeInterpreter, 1); } //if (gTraceInterpreter) postfl("<-returnFromBlock\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock"); #endif }
bool PyrGC::BlackToWhiteCheck(PyrObject *objA) { if (objA->obj_format > obj_slot) return true; // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject * objB = NULL; if (IsObj(slot) && slotRawObject(slot)) { objB = slotRawObject(slot); } if (objB && (unsigned long)objB < 100) { fprintf(stderr, "weird obj ptr\n"); return false; } if (objB) { if (objA == mStack) continue; if (objA->gc_color == mBlackColor && objA != mPartialScanObj) { if (objB->gc_color == mWhiteColor) { if (objA->classptr == class_frame) { // jmc: black stack frames pointing to white nodes can be ignore PyrFrame * frameA = (PyrFrame*)objA; PyrMethod * meth = slotRawMethod(&frameA->method); PyrMethodRaw * methraw = METHRAW(meth); if (methraw->needsHeapContext) continue; } #if DUMPINSANITY fprintf(stderr, "black frame to white ref %p %p\n", objA, objB); dumpBadObject(objA); dumpBadObject(objB); fprintf(stderr, "\n"); #endif return false; } } } } } return true; }
HOT void executeMethod(VMGlobals *g, PyrMethod *meth, long numArgsPushed) { PyrMethodRaw *methraw; PyrFrame *frame; PyrFrame *caller; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrSlot *vars; PyrObject *proto; long i, m, mmax, numtemps, numargs; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "executeMethod"); #endif #if DEBUGMETHODS if (gTraceInterpreter) { if (g->method) { postfl(" %s:%s -> %s:%s\n", slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } else { postfl(" top -> %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } } #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&meth->callMeter)++; } #endif #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 20; proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); numtemps = methraw->numtemps; numargs = methraw->numargs; caller = g->frame; //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetObject(&frame->context, frame); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, caller); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->method = meth; g->ip = slotRawInt8Array(&meth->code)->b - 1; g->frame = frame; g->block = (PyrBlock*)meth; g->sp -= numArgsPushed; qslot = g->sp; pslot = vars; if (numArgsPushed <= numargs) { /* not enough args pushed */ /* push all args to frame */ for (m=0,mmax=numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot); /* push default arg & var values */ pslot = vars + numArgsPushed; qslot = proto->slots + numArgsPushed - 1; for (m=0, mmax=numtemps - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot); } else if (methraw->varargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot); /* push list */ i = numArgsPushed - numargs; list = newPyrArray(g->gc, (int)i, 0, false); list->size = (int)i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + numargs + 1, list); /* put extra args into list */ lslot = (list->slots - 1); // fixed and raw sizes are zero for (m=0,mmax=i; m<mmax; ++m) slotCopy(++lslot, ++qslot); if (methraw->numvars) { /* push default keyword and var values */ pslot = vars + numargs + 1; qslot = proto->slots + numargs; for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot); } } else { /* push all args to frame */ for (m=0,mmax=numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot); if (methraw->numvars) { /* push default keyword and var values */ pslot = vars + numargs; qslot = proto->slots + numargs - 1; for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot); } } slotCopy(&g->receiver, &vars[1]); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "<executeMethod"); #endif }
HOT void sendMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed) { PyrMethod *meth = NULL; PyrMethodRaw *methraw; PyrSlot *recvrSlot, *sp; PyrClass *classobj; long index; PyrObject *obj; //postfl("->sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessageWithKeys"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = classOfSlot(recvrSlot); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; g->sp -= numArgsPushed - 1; sp = g->sp; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitiveWithKeys(g, meth, (int)numArgsPushed, (int)numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "<sendMessageWithKeys"); #endif //postfl("<-sendMessage\n"); }
HOT void sendSuperMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed) { PyrMethod *meth = NULL; PyrMethodRaw *methraw; PyrSlot *recvrSlot, *sp; PyrClass *classobj; long index; PyrObject *obj; //postfl("->sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendSuperMessage"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; //assert(isKindOfSlot(recvrSlot, classobj)); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstand(g, selector, numArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethod(g, meth, numArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot); numArgsPushed = methraw->numargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot); numArgsPushed = methraw->numargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot); numArgsPushed = methraw->numargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; m<mmax; ++m) slotCopy(++pslot, ++qslot); numArgsPushed = methraw->numargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitive(g, meth, (int)numArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; /* case methMultDispatchByClass : { index = methraw->specialIndex; if (index < numArgsPushed) { classobj = slotRawObject(sp + index)->classptr; selector = slotRawSymbol(&meth->selectors); goto lookup_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; case methMultDispatchByValue : { index = methraw->specialIndex; if (index < numArgsPushed) { index = arrayAtIdentityHashInPairs(array, b); meth = slotRawObject(&meth->selectors)->slots[index + 1].uom; goto meth_select_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; */ } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "<sendSuperMessage"); #endif //postfl("<-sendMessage\n"); }
HOT void returnFromMethod(VMGlobals *g) { PyrFrame *returnFrame, *curframe, *homeContext; PyrMethod *meth; PyrMethodRaw *methraw; curframe = g->frame; //assert(slotRawFrame(&curframe->context) == NULL); /*if (gTraceInterpreter) { post("returnFromMethod %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name); post("tailcall %d\n", g->tailCall); }*/ #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif homeContext = slotRawFrame(&slotRawFrame(&curframe->context)->homeContext); if (homeContext == NULL) { null_return: #if TAILCALLOPTIMIZE if (g->tailCall) return; // do nothing. #endif /* static bool once = true; if (once || gTraceInterpreter) { once = false; post("return all the way out. sd %d\n", g->sp - g->gc->Stack()->slots); postfl("%s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name ); post("tailcall %d\n", g->tailCall); post("homeContext %p\n", homeContext); post("returnFrame %p\n", returnFrame); dumpObjectSlot(&homeContext->caller); DumpStack(g, g->sp); DumpBackTrace(g); } gTraceInterpreter = false; */ //if (IsNil(&homeContext->caller)) return; // do nothing. // return all the way out. PyrSlot *bottom = g->gc->Stack()->slots; slotCopy(bottom, g->sp); g->sp = bottom; // ??!! pop everybody g->method = NULL; g->block = NULL; g->frame = NULL; longjmp(g->escapeInterpreter, 2); } else { returnFrame = slotRawFrame(&homeContext->caller); if (returnFrame == NULL) goto null_return; // make sure returnFrame is a caller and find earliest stack frame { PyrFrame *tempFrame = curframe; while (tempFrame != returnFrame) { tempFrame = slotRawFrame(&tempFrame->caller); if (!tempFrame) { if (isKindOf((PyrObject*)g->thread, class_routine) && NotNil(&g->thread->parent)) { // not found, so yield to parent thread and continue searching. PyrSlot value; slotCopy(&value, g->sp); int numArgsPushed = 1; switchToThread(g, slotRawThread(&g->thread->parent), tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. g->sp -= numArgsPushed - 1; slotCopy(g->sp, &value); curframe = tempFrame = g->frame; } else { slotCopy(&g->sp[2], &g->sp[0]); slotCopy(g->sp, &g->receiver); g->sp++; SetObject(g->sp, g->method); g->sp++; sendMessage(g, getsym("outOfContextReturn"), 3); return; } } } } { PyrFrame *tempFrame = curframe; while (tempFrame != returnFrame) { meth = slotRawMethod(&tempFrame->method); methraw = METHRAW(meth); PyrFrame *nextFrame = slotRawFrame(&tempFrame->caller); if (!methraw->needsHeapContext) { SetInt(&tempFrame->caller, 0); } else { if (tempFrame != homeContext) SetInt(&tempFrame->caller, 0); } tempFrame = nextFrame; } } // return to it g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip); g->frame = returnFrame; g->block = slotRawBlock(&returnFrame->method); homeContext = slotRawFrame(&returnFrame->homeContext); meth = slotRawMethod(&homeContext->method); methraw = METHRAW(meth); #if DEBUGMETHODS if (gTraceInterpreter) { postfl("%s:%s <- %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name ); } #endif g->method = meth; slotCopy(&g->receiver, &homeContext->vars[0]); } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif }