Replace mwscript program serialization into a vector with simple struct

Mostly to avoid string literal lookup by index with iteration over all preciding
literals and calling strlen. This is very inefficient. In genral this makes code
much more straightforward but also makes it portable since now int and float of
different sizes are properly supported.
This commit is contained in:
elsid 2023-01-10 04:10:18 +01:00
parent 60eede6a1d
commit b88f0d2dbd
No known key found for this signature in database
GPG key ID: 4DE04C198CBA7625
21 changed files with 93 additions and 162 deletions

View file

@ -5,6 +5,7 @@
#include <string>
#include "opcodes.hpp"
#include "program.hpp"
namespace Interpreter
{
@ -104,25 +105,19 @@ namespace Interpreter
}
}
void Interpreter::run(const Type_Code* code, int codeSize, Context& context)
void Interpreter::run(const Program& program, Context& context)
{
assert(codeSize >= 4);
begin();
try
{
mRuntime.configure(code, codeSize, context);
mRuntime.configure(program, context);
int opcodes = static_cast<int>(code[0]);
const Type_Code* codeBlock = code + 4;
while (mRuntime.getPC() >= 0 && mRuntime.getPC() < opcodes)
while (mRuntime.getPC() >= 0 && static_cast<std::size_t>(mRuntime.getPC()) < program.mInstructions.size())
{
Type_Code runCode = codeBlock[mRuntime.getPC()];
const Type_Code instruction = program.mInstructions[mRuntime.getPC()];
mRuntime.setPC(mRuntime.getPC() + 1);
execute(runCode);
execute(instruction);
}
}
catch (...)

View file

@ -7,12 +7,15 @@
#include <stack>
#include <utility>
#include "components/interpreter/program.hpp"
#include "opcodes.hpp"
#include "runtime.hpp"
#include "types.hpp"
namespace Interpreter
{
struct Program;
class Interpreter
{
std::stack<Runtime> mCallstack;
@ -66,7 +69,7 @@ namespace Interpreter
installSegment(mSegment5, code, std::make_unique<T>(std::forward<TArgs>(args)...));
}
void run(const Type_Code* code, int codeSize, Context& context);
void run(const Program& program, Context& context);
};
}

View file

@ -0,0 +1,20 @@
#ifndef OPENMW_COMPONENTS_INTERPRETER_PROGRAM_H
#define OPENMW_COMPONENTS_INTERPRETER_PROGRAM_H
#include "types.hpp"
#include <string>
#include <vector>
namespace Interpreter
{
struct Program
{
std::vector<Type_Code> mInstructions;
std::vector<Type_Integer> mIntegers;
std::vector<Type_Float> mFloats;
std::vector<std::string> mStrings;
};
}
#endif

View file

@ -1,4 +1,5 @@
#include "runtime.hpp"
#include "program.hpp"
#include <cassert>
#include <cstring>
@ -8,58 +9,41 @@ namespace Interpreter
{
int Runtime::getIntegerLiteral(int index) const
{
if (index < 0 || index >= static_cast<int>(mCode[1]))
throw std::out_of_range("out of range");
if (index < 0 || mProgram->mIntegers.size() <= static_cast<std::size_t>(index))
throw std::out_of_range("Invalid integer index");
const Type_Code* literalBlock = mCode + 4 + mCode[0];
return *reinterpret_cast<const int*>(&literalBlock[index]);
return mProgram->mIntegers[static_cast<std::size_t>(index)];
}
float Runtime::getFloatLiteral(int index) const
{
if (index < 0 || index >= static_cast<int>(mCode[2]))
throw std::out_of_range("out of range");
if (index < 0 || mProgram->mFloats.size() <= static_cast<std::size_t>(index))
throw std::out_of_range("Invalid float index");
const Type_Code* literalBlock = mCode + 4 + mCode[0] + mCode[1];
return *reinterpret_cast<const float*>(&literalBlock[index]);
return mProgram->mFloats[static_cast<std::size_t>(index)];
}
std::string_view Runtime::getStringLiteral(int index) const
{
if (index < 0 || static_cast<int>(mCode[3]) <= 0)
throw std::out_of_range("out of range");
if (index < 0 || mProgram->mStrings.size() <= static_cast<std::size_t>(index))
throw std::out_of_range("Invalid string literal index");
const char* literalBlock = reinterpret_cast<const char*>(mCode + 4 + mCode[0] + mCode[1] + mCode[2]);
size_t offset = 0;
for (; index; --index)
{
offset += std::strlen(literalBlock + offset) + 1;
if (offset / 4 >= mCode[3])
throw std::out_of_range("out of range");
}
return literalBlock + offset;
return mProgram->mStrings[static_cast<std::size_t>(index)];
}
void Runtime::configure(const Type_Code* code, int codeSize, Context& context)
void Runtime::configure(const Program& program, Context& context)
{
clear();
mContext = &context;
mCode = code;
mCodeSize = codeSize;
mProgram = &program;
mPC = 0;
}
void Runtime::clear()
{
mContext = nullptr;
mCode = nullptr;
mCodeSize = 0;
mProgram = nullptr;
mStack.clear();
}

View file

@ -9,14 +9,14 @@
namespace Interpreter
{
class Context;
struct Program;
/// Runtime data and engine interface
class Runtime
{
Context* mContext = nullptr;
const Type_Code* mCode = nullptr;
int mCodeSize = 0;
const Program* mProgram = nullptr;
int mPC = 0;
std::vector<Data> mStack;
@ -30,9 +30,9 @@ namespace Interpreter
std::string_view getStringLiteral(int index) const;
void configure(const Type_Code* code, int codeSize, Context& context);
void configure(const Program& program, Context& context);
///< \a context and \a code must exist as least until either configure, clear or
/// the destructor is called. \a codeSize is given in 32-bit words.
/// the destructor is called.
void clear();