void BytecodeVisitor::visitStoreNode(StoreNode *node) { LOG_Visitor("visitStoreNode"); VariableInContextDescriptor variableDescriptor = context->getVariableDescriptor(node->var()->name()); if (node->op() == tINCRSET || node->op() == tDECRSET) { loadVariable(variableDescriptor, node); } node->value()->visit(this); VarType varType = context->getVariableByID(variableDescriptor)->type(); cast(varType, node, "storing node"); switch (node->op()) { case tINCRSET: bc()->addInsn(varType == VT_DOUBLE ? BC_DADD : BC_IADD); break; case tDECRSET: bc()->addInsn(BC_SWAP); bc()->addInsn(varType == VT_DOUBLE ? BC_DSUB : BC_ISUB); break; case tASSIGN: break; default: throw TranslationError("Incorrect storing variable operation", node->position()); } storeVariable(variableDescriptor, node); }
void Story::callRoutine(Address routineAddress, Word returnVariable, const std::vector<Word> &arguments) { // NOTE: special case! A call to address 0 means return false! if(routineAddress == 0) { returnFromCall(0); return; // NOTE: Early return } Address returnAddress = m_PC; auto normalizedAddress = expandPackedRoutineAddress(routineAddress); // Point to the new routine setPC(normalizedAddress); auto numberOfLocals = readNextByte(); auto stackFrame = allocateNewFrame(returnAddress, arguments.size(), numberOfLocals, returnVariable); // The local default values are stored next if(m_Version <= 4) { // The defaults are next for(Byte i = 0; i < numberOfLocals; i++) { auto value = readNextWord(); storeVariable(i + 1, value); } } else { // They all default to 0 for(Byte i = 0; i < numberOfLocals; i++) { storeVariable(i + 1, 0); } } // Now layer the arguments on top auto argumentsToCopy = std::min(numberOfLocals, static_cast<Byte>(arguments.size())); for(Byte i = 0; i < argumentsToCopy; i++) { storeVariable(i + 1, arguments[i]); } }
void BytecodeVisitor::visitForNode(ForNode *node) { LOG_Visitor("visitForNode"); VariableInContextDescriptor variableDescriptor = context->getVariableDescriptor(node->var()->name()); BinaryOpNode *innerExpression = (BinaryOpNode *) node->inExpr(); if (innerExpression->kind() != tRANGE) { throw TranslationError(string("Incorrect binary operation in for-expression. Exptected: RANGE, got: ") + tokenStr(innerExpression->kind()), node->position()); } if (node->var()->type() != VT_INT) { throw TranslationError(string("Incorrect type of for-variable. Exptected: INT, got: ") + typeToName(node->var()->type()), node->position()); } innerExpression->left()->visit(this); bc()->addInsn(BC_ILOADM1); bc()->addInsn(BC_IADD); storeVariable(variableDescriptor, innerExpression); Label begin(bc()); Label end(bc()); { bc()->bind(begin); loadVariable(variableDescriptor, innerExpression); bc()->addInsn(BC_ILOAD1); bc()->addInsn(BC_IADD); storeVariable(variableDescriptor, innerExpression); //condition innerExpression->right()->visit(this); loadVariable(variableDescriptor, innerExpression); bc()->addInsn(BC_SWAP); // goto end if greater bc()->addBranch(BC_IFICMPG, end); node->body()->visit(this); bc()->addBranch(BC_JA, begin); } bc()->bind(end); }
void Story::storeVariableInPlace(Byte variableID, Word value) { if(variableID == 0) { // We write over the top of the stack pop(); push(value); } else { storeVariable(variableID, value); } }
void DtoNestedInit(VarDeclaration* vd) { Logger::println("DtoNestedInit for %s", vd->toChars()); LOG_SCOPE IrFunction* irfunc = gIR->func()->decl->ir.irFunc; LLValue* nestedVar = irfunc->nestedVar; if (nestedCtx == NCArray) { // alloca as usual if no value already if (!vd->ir.irLocal->value) vd->ir.irLocal->value = DtoAlloca(vd->type, vd->toChars()); // store the address into the nested vars array assert(vd->ir.irLocal->nestedIndex >= 0); LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex); assert(isaPointer(vd->ir.irLocal->value)); LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); DtoAlignedStore(val, gep); } else if (nestedCtx == NCHybrid) { assert(vd->ir.irLocal->value && "Nested variable without storage?"); if (!vd->isParameter() && (vd->isRef() || vd->isOut())) { unsigned vardepth = vd->ir.irLocal->nestedDepth; LLValue* val = NULL; // Retrieve frame pointer if (vardepth == irfunc->depth) { val = nestedVar; } else { FuncDeclaration *parentfunc = getParentFunc(vd, true); assert(parentfunc && "No parent function for nested variable?"); val = DtoGEPi(nestedVar, 0, vardepth); val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str()); } val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); storeVariable(vd, val); } else { // Already initialized in DtoCreateNestedContext } } else { assert(0 && "Not implemented yet"); } }
void Story::returnFromCall(Word result) { // First up, put the stack and PC back to what they should be auto returnFrame = m_Frames.top(); m_Frames.pop(); m_StackSpace.revertToFrame(returnFrame); setPC(returnFrame.getReturnAddress()); // The result goes back into a variable... auto resultVariableID = returnFrame.getResultVariable(); if(resultVariableID != DiscardResultsVariable) { storeVariable(static_cast<Byte>(resultVariableID), result); } }
void SimpleInterpreter::run(ostream &out) { stack.resize(50); bytecodes.clear(); indices.clear(); vars.clear(); bytecodes.push_back(bytecode); indices.push_back(0); contextID.push_back(0); callsCounter.push_back(0); SP = 0; while (!bytecodes.empty()) { indexType ¤tIndex = indices.back(); Bytecode &bytecode = *bytecodes.back(); Instruction instruction = bytecode.getInsn(currentIndex); size_t instructionLength = bytecodeLength(instruction); #ifdef LOG_INTERPRETER const char* bcName = bytecodeName(instruction, 0); cout << "index: " << currentIndex << ", instruction: " << bcName << endl; #endif switch (instruction) { case BC_DLOAD: pushVariable(bytecode.getDouble(currentIndex + 1)); break; case BC_ILOAD: pushVariable(bytecode.getInt64(currentIndex + 1)); break; case BC_SLOAD: pushVariable(constantById(bytecode.getUInt16(currentIndex + 1)).c_str()); break; case BC_DLOAD0: pushVariable(0.0); break; case BC_ILOAD0: pushVariable((signedIntType) 0); break; case BC_SLOAD0: pushVariable(""); break; case BC_DLOAD1: pushVariable(1.0); break; case BC_ILOAD1: pushVariable((signedIntType) 1); break; case BC_DLOADM1: pushVariable(-1.0); break; case BC_ILOADM1: pushVariable((signedIntType) - 1); break; case BC_DADD: binary_operation(VT_DOUBLE, add<double>); break; case BC_IADD: binary_operation(VT_INT, add < signedIntType > ); break; case BC_DSUB: binary_operation(VT_DOUBLE, sub<double>); break; case BC_ISUB: binary_operation(VT_INT, sub < signedIntType > ); break; case BC_DMUL: binary_operation(VT_DOUBLE, mul<double>); break; case BC_IMUL: binary_operation(VT_INT, mul < signedIntType > ); break; case BC_DDIV: binary_operation(VT_DOUBLE, _div<double>); break; case BC_IDIV: binary_operation(VT_INT, _div < signedIntType > ); break; case BC_IMOD: binary_operation(VT_INT, mod < signedIntType > ); break; case BC_DNEG: unary_operation(VT_DOUBLE, neg<double>); break; case BC_INEG: unary_operation(VT_INT, neg < signedIntType > ); break; case BC_IAOR: binary_operation(VT_INT, _or < signedIntType > ); break; case BC_IAAND: binary_operation(VT_INT, _and < signedIntType > ); break; case BC_IAXOR: binary_operation(VT_INT, _xor < signedIntType > ); break; case BC_IPRINT: out << popVariable().getIntValue(); out.flush(); break; case BC_DPRINT: out << popVariable().getDoubleValue(); out.flush(); break; case BC_SPRINT: out << popVariable().getStringValue(); out.flush(); break; case BC_SWAP: { auto v1 = popVariable(); auto v2 = popVariable(); pushVariable(v1); pushVariable(v2); break; } case BC_STOREDVAR0: case BC_STOREIVAR0: case BC_STORESVAR0: storeVariable(0); break; case BC_STOREDVAR1: case BC_STOREIVAR1: case BC_STORESVAR1: storeVariable(1); break; case BC_STOREDVAR2: case BC_STOREIVAR2: case BC_STORESVAR2: storeVariable(2); break; case BC_STOREDVAR3: case BC_STOREIVAR3: case BC_STORESVAR3: storeVariable(3); break; case BC_LOADDVAR: case BC_LOADIVAR: case BC_LOADSVAR: pushVariable(loadVariable(bytecode.getUInt16(currentIndex + 1))); break; case BC_LOADDVAR0: case BC_LOADIVAR0: case BC_LOADSVAR0: pushVariable(loadVariable(0)); break; case BC_LOADDVAR1: case BC_LOADIVAR1: case BC_LOADSVAR1: pushVariable(loadVariable(1)); break; case BC_LOADIVAR2: case BC_LOADSVAR2: case BC_LOADDVAR2: pushVariable(loadVariable(2)); break; case BC_LOADDVAR3: case BC_LOADIVAR3: case BC_LOADSVAR3: pushVariable(loadVariable(3)); break; case BC_STOREDVAR: case BC_STOREIVAR: case BC_STORESVAR: storeVariable(bytecode.getUInt16(currentIndex + 1)); break; case BC_LOADCTXDVAR: case BC_LOADCTXIVAR: case BC_LOADCTXSVAR: pushVariable(loadVariable(bytecode.getUInt16(currentIndex + 1), bytecode.getUInt16(currentIndex + 3))); break; case BC_STORECTXDVAR: case BC_STORECTXIVAR: case BC_STORECTXSVAR: storeVariable(bytecode.getUInt16(currentIndex + 1), bytecode.getUInt16(currentIndex + 3)); break; case BC_DCMP: binary_operation<double, signedIntType>(VT_DOUBLE, _cmp<double>); break; case BC_ICMP: binary_operation(VT_INT, _cmp < signedIntType > ); break; case BC_JA: { currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_IFICMPNE: { if (!check_condition(_neq<signedIntType>)) break; currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_IFICMPE: { if (!check_condition(_eq<signedIntType>)) break; currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_IFICMPG: { if (!check_condition(_g<signedIntType>)) break; currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_IFICMPGE: { if (!check_condition(_ge<signedIntType>)) break; currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_IFICMPL: { if (!check_condition(_l<signedIntType>)) break; currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_IFICMPLE: { if (!check_condition(_le<signedIntType>)) break; currentIndex += bytecode.getInt16(currentIndex + 1) + 1; continue; } case BC_STOP: { indices.clear(); bytecodes.clear(); continue; } case BC_CALLNATIVE: { callNative(bytecode.getUInt16(currentIndex + 1)); break; } case BC_CALL: { TranslatedFunction *f = functionById(bytecode.getUInt16(currentIndex + 1)); bytecodes.push_back(static_cast<BytecodeFunction *>(f)->bytecode()); indices.push_back(0); contextID.push_back(f->id()); detectCallWithFunctionID(contextID.back()); continue; } case BC_RETURN: { indices.pop_back(); bytecodes.pop_back(); if (!indices.empty()) { indices.back() += bytecodeLength(BC_CALL); } if (callsCounter[contextID.back()] > 0) { callsCounter[contextID.back()]--; } contextID.pop_back(); continue; } case BC_I2D: pushVariable((double) popVariable().getIntValue()); break; case BC_D2I: pushVariable((signedIntType) popVariable().getDoubleValue()); break; case BC_S2I: pushVariable((signedIntType) popVariable().getStringValue()); break; case BC_BREAK: break; case BC_INVALID: throw InterpretationError("BC_Invalid instruction"); default: throw InterpretationError(string("Unknown interpreting instruction: ") + bytecodeName(instruction, 0)); } currentIndex += instructionLength; } }
void storeVariable(unsignedIntType id) { storeVariable(contextID.back(), id); }
void DtoCreateNestedContext(FuncDeclaration* fd) { Logger::println("DtoCreateNestedContext for %s", fd->toChars()); LOG_SCOPE DtoCreateNestedContextType(fd); // construct nested variables array if (!fd->nestedVars.empty()) { IrFunction* irfunction = fd->ir.irFunc; unsigned depth = irfunction->depth; LLStructType *frameType = irfunction->frameType; // Create frame for current function and append to frames list // FIXME: alignment ? LLValue* frame = 0; if (fd->needsClosure()) frame = DtoGcMalloc(frameType, ".frame"); else frame = DtoRawAlloca(frameType, 0, ".frame"); // copy parent frames into beginning if (depth != 0) { LLValue* src = irfunction->nestArg; if (!src) { assert(irfunction->thisArg); assert(fd->isMember2()); LLValue* thisval = DtoLoad(irfunction->thisArg); AggregateDeclaration* cd = fd->isMember2(); assert(cd); assert(cd->vthis); Logger::println("Indexing to 'this'"); if (cd->isStructDeclaration()) src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); else src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); } else { src = DtoLoad(src); } if (depth > 1) { src = DtoBitCast(src, getVoidPtrType()); LLValue* dst = DtoBitCast(frame, getVoidPtrType()); DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), getABITypeAlign(getVoidPtrType())); } // Copy nestArg into framelist; the outer frame is not in the list of pointers src = DtoBitCast(src, frameType->getContainedType(depth-1)); LLValue* gep = DtoGEPi(frame, 0, depth-1); DtoAlignedStore(src, gep); } // store context in IrFunction irfunction->nestedVar = frame; // go through all nested vars and assign addresses where possible. for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { VarDeclaration* vd = *i; LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); if (vd->isParameter()) { Logger::println("nested param: %s", vd->toChars()); LOG_SCOPE IrParameter* parm = vd->ir.irParam; if (parm->arg->byref) { storeVariable(vd, gep); } else { Logger::println("Copying to nested frame"); // The parameter value is an alloca'd stack slot. // Copy to the nesting frame and leave the alloca for // the optimizers to clean up. DtoStore(DtoLoad(parm->value), gep); gep->takeName(parm->value); parm->value = gep; } } else { Logger::println("nested var: %s", vd->toChars()); assert(!vd->ir.irLocal->value); vd->ir.irLocal->value = gep; } if (global.params.symdebug) { LLSmallVector<LLValue*, 2> addr; dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); DtoDwarfLocalVariable(frame, vd, addr); } } } }
void DtoCreateNestedContext(FuncDeclaration* fd) { Logger::println("DtoCreateNestedContext for %s", fd->toChars()); LOG_SCOPE DtoCreateNestedContextType(fd); if (nestedCtx == NCArray) { // construct nested variables array if (!fd->nestedVars.empty()) { Logger::println("has nested frame"); // start with adding all enclosing parent frames until a static parent is reached int nparelems = 0; if (!fd->isStatic()) { Dsymbol* par = fd->toParent2(); while (par) { if (FuncDeclaration* parfd = par->isFuncDeclaration()) { nparelems += parfd->nestedVars.size(); // stop at first static if (parfd->isStatic()) break; } else if (par->isClassDeclaration()) { // nothing needed } else { break; } par = par->toParent2(); } } int nelems = fd->nestedVars.size() + nparelems; // make array type for nested vars LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems); // alloca it // FIXME align ? LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars"); IrFunction* irfunction = fd->ir.irFunc; // copy parent frame into beginning if (nparelems) { LLValue* src = irfunction->nestArg; if (!src) { assert(irfunction->thisArg); assert(fd->isMember2()); LLValue* thisval = DtoLoad(irfunction->thisArg); ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); assert(cd); assert(cd->vthis); src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis")); } else { src = DtoLoad(src); } DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE), getABITypeAlign(getVoidPtrType())); } // store in IrFunction irfunction->nestedVar = nestedVars; // go through all nested vars and assign indices int idx = nparelems; for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { VarDeclaration* vd = *i; if (!vd->ir.irLocal) vd->ir.irLocal = new IrLocal(vd); if (vd->isParameter()) { Logger::println("nested param: %s", vd->toChars()); LLValue* gep = DtoGEPi(nestedVars, 0, idx); LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType()); DtoAlignedStore(val, gep); } else { Logger::println("nested var: %s", vd->toChars()); } vd->ir.irLocal->nestedIndex = idx++; } } } else if (nestedCtx == NCHybrid) { // construct nested variables array if (!fd->nestedVars.empty()) { IrFunction* irfunction = fd->ir.irFunc; unsigned depth = irfunction->depth; LLStructType *frameType = irfunction->frameType; // Create frame for current function and append to frames list // FIXME: alignment ? LLValue* frame = 0; #if DMDV2 if (fd->needsClosure()) frame = DtoGcMalloc(frameType, ".frame"); else #endif frame = DtoRawAlloca(frameType, 0, ".frame"); // copy parent frames into beginning if (depth != 0) { LLValue* src = irfunction->nestArg; if (!src) { assert(irfunction->thisArg); assert(fd->isMember2()); LLValue* thisval = DtoLoad(irfunction->thisArg); #if DMDV2 AggregateDeclaration* cd = fd->isMember2(); #else ClassDeclaration* cd = fd->isMember2()->isClassDeclaration(); #endif assert(cd); assert(cd->vthis); Logger::println("Indexing to 'this'"); #if DMDV2 if (cd->isStructDeclaration()) src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis"); else #endif src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis")); } else { src = DtoLoad(src); } if (depth > 1) { src = DtoBitCast(src, getVoidPtrType()); LLValue* dst = DtoBitCast(frame, getVoidPtrType()); DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE), getABITypeAlign(getVoidPtrType())); } // Copy nestArg into framelist; the outer frame is not in the list of pointers src = DtoBitCast(src, frameType->getContainedType(depth-1)); LLValue* gep = DtoGEPi(frame, 0, depth-1); DtoAlignedStore(src, gep); } // store context in IrFunction irfunction->nestedVar = frame; // go through all nested vars and assign addresses where possible. for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i) { VarDeclaration* vd = *i; LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars()); if (vd->isParameter()) { Logger::println("nested param: %s", vd->toChars()); LOG_SCOPE LLValue* value = vd->ir.irLocal->value; if (llvm::isa<llvm::AllocaInst>(llvm::GetUnderlyingObject(value))) { Logger::println("Copying to nested frame"); // The parameter value is an alloca'd stack slot. // Copy to the nesting frame and leave the alloca for // the optimizers to clean up. assert(!vd->ir.irLocal->byref); DtoStore(DtoLoad(value), gep); gep->takeName(value); vd->ir.irLocal->value = gep; } else { Logger::println("Adding pointer to nested frame"); // The parameter value is something else, such as a // passed-in pointer (for 'ref' or 'out' parameters) or // a pointer arg with byval attribute. // Store the address into the frame. assert(vd->ir.irLocal->byref); storeVariable(vd, gep); } } else if (vd->isRef() || vd->isOut()) { // This slot is initialized in DtoNestedInit, to handle things like byref foreach variables // which move around in memory. assert(vd->ir.irLocal->byref); } else { Logger::println("nested var: %s", vd->toChars()); if (vd->ir.irLocal->value) Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n'; assert(!vd->ir.irLocal->value); vd->ir.irLocal->value = gep; assert(!vd->ir.irLocal->byref); } if (global.params.symdebug) { LLSmallVector<LLValue*, 2> addr; dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex); DtoDwarfLocalVariable(frame, vd, addr); } } } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) { // Propagate context arg properties if the context arg is passed on unmodified. DtoDeclareFunction(parFunc); fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType; fd->ir.irFunc->depth = parFunc->ir.irFunc->depth; } } else { assert(0 && "Not implemented yet"); } }