void prepareDrawElementsEntry( RenderEngineGLIndirect::RenderGroupGLCache::DrawElementsListEntry *entry ) { entry->m_indirectCommandsBuffer = nullptr; handleAssign( entry->m_indirectCommandsBuffer, BufferGL::create( dp::rix::core::BufferDescription() ) ); entry->m_indirectCommandsBuffer->updateData( 0, &entry->m_indirectCommands[0], entry->m_indirectCommands.size() * sizeof(RenderEngineGLIndirect::RenderGroupGLCache::DrawElementsIndirectCommand) ); entry->m_indirectEntriesBuffer = nullptr; handleAssign( entry->m_indirectEntriesBuffer, BufferGL::create( dp::rix::core::BufferDescription() ) ); entry->m_indirectEntriesBuffer->updateData( 0, &entry->m_indirectEntries[0], entry->m_indirectEntries.size() * sizeof(RenderEngineGLIndirect::RenderGroupGLCache::IndirectEntry)); entry->m_indirectPointersBuffer = nullptr; handleAssign( entry->m_indirectPointersBuffer, BufferGL::create( dp::rix::core::BufferDescription() ) ); std::vector<GLuint64EXT> pointers; DP_ASSERT( entry->m_indirectEntriesBuffer->getBuffer() ); dp::gl::BufferSharedPtr const& buffer = entry->m_indirectEntriesBuffer->getBuffer(); GLuint64EXT base = buffer->getAddress(); for ( size_t index = 0;index < entry->m_indirectEntries.size(); ++index ) { pointers.push_back( base + index * sizeof(RenderEngineGLIndirect::RenderGroupGLCache::IndirectEntry) ); } entry->m_indirectPointersBuffer->updateData( 0, &pointers[0], pointers.size() * sizeof(GLuint64EXT) ); entry->m_indirectPointersBufferAddress = base; entry->m_indirectPointersBufferRange = buffer->getSize(); }
Value Interpreter::exec(const InstructionList &instructions, Bindings &bindings) { Stack stack; ClosureValues closureValues; for(InstructionList::const_iterator it = instructions.begin() ; it != instructions.end() ; ++it) { Instruction::Type type = it->type(); const Value &value = it->value(); switch(type) { case Instruction::PUSH: if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " push " << value << '\n'; } stack.push_back(value); break; case Instruction::CALL: { if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " call " << value << '\n'; } Value result = handleFunction(it->sourceLocation(), value, stack, bindings); stack.push_back(result); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " return value " << result << '\n'; } } break; case Instruction::JUMP: { int instructionsToSkip = getInstructionsToSkip(type, value); int remaining = instructions.end() - it; if(remaining < instructionsToSkip) { throw CompilerBug("insufficient instructions available to skip! (remaining: " + str(remaining) + " < instructionsToSkip: " + str(instructionsToSkip) + ")"); } if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " jumping back " << instructionsToSkip << '\n'; } it += instructionsToSkip; } break; case Instruction::LOOP: { int instructionsToSkip = getInstructionsToSkip(type, value); int instructionsAvailable = instructions.size(); // Note: signed type is important! if(instructionsAvailable < instructionsToSkip) { throw CompilerBug("insufficient instructions available to loop! (instructionsToSkip: " + str(instructionsToSkip) + " > instructions.size(): " + str(instructions.size()) + ")"); } if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " looping back " << instructionsToSkip << " instructions\n"; } it -= instructionsToSkip; } break; case Instruction::CLOSE: { if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " close " << value << '\n'; } Value result = handleClose(value, stack, closureValues, bindings); stack.push_back(result); } break; case Instruction::COND_JUMP: { if(stack.empty()) { throw CompilerBug("empty stack when testing conditional jump"); } int instructionsToSkip = getInstructionsToSkip(type, value); int remaining = instructions.end() - it; if(remaining < instructionsToSkip) { throw CompilerBug("insufficient instructions available to skip! (remaining: " + str(remaining) + " < instructionsToSkip: " + str(instructionsToSkip) + ")"); } Value top = pop(stack); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " jumping back " << instructionsToSkip << " if " << top << '\n'; } if(top.isFalsey()) { it += instructionsToSkip; } } break; case Instruction::REF_LOCAL: handleRef(Bindings::Local, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " local ref '" << value.string() << "' is " << stack.back() << '\n'; } break; case Instruction::INIT_LOCAL: { const Value &intialisedValue = handleInit(Bindings::Local, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " local init '" << value.string() << "' to " << intialisedValue << '\n'; } } break; case Instruction::ASSIGN_LOCAL: { const Value &assignedValue = handleAssign(Bindings::Local, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " local assign '" << value.string() << "' to " << assignedValue << '\n'; } } break; case Instruction::REF_GLOBAL: handleRef(Bindings::Global, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " global ref '" << value.string() << "' is " << stack.back() << '\n'; } break; case Instruction::INIT_GLOBAL: { const Value &intialisedValue = handleInit(Bindings::Global, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " global init '" << value.string() << "' to " << intialisedValue << '\n'; } } break; case Instruction::ASSIGN_GLOBAL: { const Value &assignedValue = handleAssign(Bindings::Global, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " global assign '" << value.string() << "' to " << assignedValue << '\n'; } } break; case Instruction::REF_CLOSURE: handleRef(Bindings::Closure, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " closure ref '" << value.string() << "' is " << stack.back() << '\n'; } break; case Instruction::INIT_CLOSURE: { Identifier identifier = Identifier(value.string()); Bindings::ValuePtr &binding = bindings.getPointer(identifier); closureValues.push_back(ClosedNameAndValue(identifier, binding)); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " closure init '" << value.string() << "' is " << *binding << '\n'; } } break; case Instruction::ASSIGN_CLOSURE: { const Value &assignedValue = handleAssign(Bindings::Closure, value, stack, bindings); if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " closure assign '" << value.string() << "' to " << assignedValue << '\n'; } } break; case Instruction::MEMBER_ACCESS: { if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " member access " << value << '\n'; } assert(value.isString()); const std::string &memberName = value.string(); Value top = pop(stack); if(!top.isObject()) { throw ExecutionError(it->sourceLocation(), "Member access instruction requires an object but got " + str(top)); } const Value::Object &object = top.object(); Value::Object::const_iterator memberIterator = object.find(memberName); if (memberIterator == object.end()) { throw ExecutionError(it->sourceLocation(), "Unknown member name " + memberName + " for " + str(top)); } if(settings_.trace) { std::cout << "DEBUG: " << it->sourceLocation() << " member access " << value.string() << "." << memberName << " was " << memberIterator->second << '\n'; } stack.push_back(memberIterator->second); } break; default: throw CompilerBug("unhandled instruction type: " + str(type)); } if (settings_.trace) { if (stack.empty()) { std::cout << "Stack is empty\n"; } else { std::cout << "Stack contains " << stack.size() << " entries:\n"; int index = 0; for(Stack::const_iterator it = stack.begin() ; it != stack.end() ; ++it) { ++index; std::cout << index << ": " << *it << '\n'; } } if (closureValues.empty()) { std::cout << "closureValues is empty\n"; } else { std::cout << "closureValues contains " << closureValues.size() << " entries:\n"; int index = 0; for(const ClosedNameAndValue &closedValue: closureValues) { ++index; std::cout << index << ": " << closedValue.first << " -> " << *closedValue.second << " @ " << closedValue.second << '\n'; } } } } return stack.empty() ? Value::nil() : pop(stack); }