void Interpreter::popFrameAndPushResult(vm_oop_t result) { VMFrame* prevFrame = popFrame(); VMMethod* method = prevFrame->GetMethod(); long numberOfArgs = method->GetNumberOfArguments(); for (long i = 0; i < numberOfArgs; ++i) GetFrame()->Pop(); GetFrame()->Push(result); }
void CloneObjectsTest::testCloneBlock() { VMSymbol* methodSymbol = GetUniverse()->NewSymbol("someMethod"); VMMethod* method = GetUniverse()->NewMethod(methodSymbol, 0, 0); VMBlock* orig = GetUniverse()->NewBlock(method, GetUniverse()->GetInterpreter()->GetFrame(), method->GetNumberOfArguments()); VMBlock* 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("blockMethod differs!!", orig->blockMethod, clone->blockMethod); CPPUNIT_ASSERT_EQUAL_MESSAGE("context differs!!", orig->context, clone->context); }
void Interpreter::doPushBlock(long bytecodeIndex) { // Short cut the negative case of #ifTrue: and #ifFalse: if (currentBytecodes[bytecodeIndexGlobal] == BC_SEND) { if (GetFrame()->GetStackElement(0) == load_ptr(falseObject) && method->GetConstant(bytecodeIndexGlobal) == load_ptr(symbolIfTrue)) { GetFrame()->Push(load_ptr(nilObject)); return; } else if (GetFrame()->GetStackElement(0) == load_ptr(trueObject) && method->GetConstant(bytecodeIndexGlobal) == load_ptr(symbolIfFalse)) { GetFrame()->Push(load_ptr(nilObject)); return; } } VMMethod* blockMethod = static_cast<VMMethod*>(method->GetConstant(bytecodeIndex)); long numOfArgs = blockMethod->GetNumberOfArguments(); GetFrame()->Push(GetUniverse()->NewBlock(blockMethod, GetFrame(), numOfArgs)); }
void Interpreter::doReturnNonLocal() { vm_oop_t result = GetFrame()->Pop(); VMFrame* context = GetFrame()->GetOuterContext(); if (!context->HasPreviousFrame()) { VMBlock* block = static_cast<VMBlock*>(GetFrame()->GetArgument(0, 0)); VMFrame* prevFrame = GetFrame()->GetPreviousFrame(); VMFrame* outerContext = prevFrame->GetOuterContext(); vm_oop_t sender = outerContext->GetArgument(0, 0); vm_oop_t arguments[] = {block}; popFrame(); // Pop old arguments from stack VMMethod* method = GetFrame()->GetMethod(); long numberOfArgs = method->GetNumberOfArguments(); for (long i = 0; i < numberOfArgs; ++i) GetFrame()->Pop(); // check if current frame is big enough for this unplanned send // #escapedBlock: needs 2 slots, one for self, and one for the block long additionalStackSlots = 2 - GetFrame()->RemainingStackSize(); if (additionalStackSlots > 0) { GetFrame()->SetBytecodeIndex(bytecodeIndexGlobal); // copy current frame into a bigger one, and replace it SetFrame(VMFrame::EmergencyFrameFrom(GetFrame(), additionalStackSlots)); } AS_OBJ(sender)->Send(escapedBlock, arguments, 1); return; } while (GetFrame() != context) popFrame(); popFrameAndPushResult(result); }