void Interpreter::doSuperSend(long bytecodeIndex) { VMSymbol* signature = static_cast<VMSymbol*>(method->GetConstant(bytecodeIndex)); VMFrame* ctxt = GetFrame()->GetOuterContext(); VMMethod* realMethod = ctxt->GetMethod(); VMClass* holder = realMethod->GetHolder(); VMClass* super = holder->GetSuperClass(); VMInvokable* invokable = static_cast<VMInvokable*>(super->LookupInvokable(signature)); if (invokable != nullptr) (*invokable)(GetFrame()); else { long numOfArgs = Signature::GetNumberOfArguments(signature); vm_oop_t receiver = GetFrame()->GetStackElement(numOfArgs - 1); VMArray* argumentsArray = GetUniverse()->NewArray(numOfArgs); for (long i = numOfArgs - 1; i >= 0; --i) { vm_oop_t o = GetFrame()->Pop(); argumentsArray->SetIndexableField(i, o); } vm_oop_t arguments[] = {signature, argumentsArray}; AS_OBJ(receiver)->Send(doesNotUnderstand, arguments, 2); } }
void CloneObjectsTest::testCloneArray() { VMArray* orig = GetUniverse()->NewArray(3); orig->SetIndexableField(0, GetUniverse()->NewString("foobar42")); orig->SetIndexableField(1, GetUniverse()->NewString("foobar43")); orig->SetIndexableField(2, GetUniverse()->NewString("foobar44")); VMArray* clone = orig->Clone(); CPPUNIT_ASSERT((intptr_t)orig != (intptr_t)clone); CPPUNIT_ASSERT_EQUAL_MESSAGE("class differs!!", orig->clazz, clone->clazz); CPPUNIT_ASSERT_EQUAL_MESSAGE("objectSize differs!!", orig->objectSize, clone->objectSize); CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfFields differs!!", orig->numberOfFields, clone->numberOfFields); CPPUNIT_ASSERT_EQUAL_MESSAGE("numberOfFields differs!!", orig->GetNumberOfIndexableFields(), clone->GetNumberOfIndexableFields()); CPPUNIT_ASSERT_EQUAL_MESSAGE("field 0 differs", orig->GetIndexableField(0), clone->GetIndexableField(0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("field 1 differs", orig->GetIndexableField(1), clone->GetIndexableField(1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("field 2 differs", orig->GetIndexableField(2), clone->GetIndexableField(2)); }
void Interpreter::send(VMSymbol* signature, VMClass* receiverClass) { VMInvokable* invokable = receiverClass->LookupInvokable(signature); if (invokable != nullptr) { #ifdef LOG_RECEIVER_TYPES StdString name = receiverClass->GetName()->GetStdString(); if (GetUniverse()->callStats.find(name) == GetUniverse()->callStats.end()) GetUniverse()->callStats[name] = {0,0}; GetUniverse()->callStats[name].noCalls++; if (invokable->IsPrimitive()) GetUniverse()->callStats[name].noPrimitiveCalls++; #endif // since an invokable is able to change/use the frame, we have to write // cached values before, and read cached values after calling GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal); (*invokable)(GetFrame()); bytecodeIndexGlobal = GetFrame()->GetBytecodeIndex(); } else { GetFrame()->PrintStackTrace(); //doesNotUnderstand long numberOfArgs = Signature::GetNumberOfArguments(signature); vm_oop_t receiver = GetFrame()->GetStackElement(numberOfArgs-1); VMArray* argumentsArray = GetUniverse()->NewArray(numberOfArgs - 1); // without receiver // the receiver should not go into the argumentsArray // so, numberOfArgs - 2 for (long i = numberOfArgs - 2; i >= 0; --i) { vm_oop_t o = GetFrame()->Pop(); argumentsArray->SetIndexableField(i, o); } vm_oop_t arguments[] = {signature, argumentsArray}; GetFrame()->Pop(); // pop the receiver //check if current frame is big enough for this unplanned Send //doesNotUnderstand: needs 3 slots, one for this, one for method name, one for args long additionalStackSlots = 3 - GetFrame()->RemainingStackSize(); if (additionalStackSlots > 0) { GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal); //copy current frame into a bigger one and replace the current frame SetFrame(VMFrame::EmergencyFrameFrom(GetFrame(), additionalStackSlots)); } AS_OBJ(receiver)->Send(doesNotUnderstand, arguments, 2); } }