示例#1
0
int identDictPut(struct VMGlobals *g, PyrObject *dict, PyrSlot *key, PyrSlot *value)
{
	PyrSlot *slot, *newslot;
	int i, index, size;
	PyrObject *array;

	bool knows = IsTrue(dict->slots + ivxIdentDict_know);
	if (knows && IsSym(key)) {
		if (slotRawSymbol(key) == s_parent) {
			slotCopy(&dict->slots[ivxIdentDict_parent],value);
			g->gc->GCWrite(dict, value);
			return errNone;
		}
		if (slotRawSymbol(key) == s_proto) {
			slotCopy(&dict->slots[ivxIdentDict_proto],value);
			g->gc->GCWrite(dict, value);
			return errNone;
		}
	}
	array = slotRawObject(&dict->slots[ivxIdentDict_array]);
	if (array->IsImmutable()) return errImmutableObject;
	if (!isKindOf((PyrObject*)array, class_array)) return errFailed;

	index = arrayAtIdentityHashInPairs(array, key);
	slot = array->slots + index;
	slotCopy(&slot[1],value);
	g->gc->GCWrite(array, value);
	if (IsNil(slot)) {
		slotCopy(slot,key);
		g->gc->GCWrite(array, key);
		size = slotRawInt(&dict->slots[ivxIdentDict_size]) + 1;
		SetRaw(&dict->slots[ivxIdentDict_size], size);
		if (array->size < size*3) {
			PyrObject *newarray;
			newarray = newPyrArray(g->gc, size*3, 0, false);
			newarray->size = ARRAYMAXINDEXSIZE(newarray);
			nilSlots(newarray->slots, newarray->size);
			slot = array->slots;
			for (i=0; i<array->size; i+=2, slot+=2) {
				if (NotNil(slot)) {
					index = arrayAtIdentityHashInPairs(newarray, slot);
					newslot = newarray->slots + index;
					slotCopy(&newslot[0],&slot[0]);
					slotCopy(&newslot[1],&slot[1]);
				}
			}
			SetRaw(&dict->slots[ivxIdentDict_array], newarray);
			g->gc->GCWriteNew(dict, newarray); // we know newarray is white so we can use GCWriteNew
		}
	}
	return errNone;
}
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");
}