Commit f2e40598 authored by Alexander A. Maly's avatar Alexander A. Maly

Refactoring VM

parent 556a68d5
Pipeline #1945 failed with stages
in 2 minutes and 34 seconds
add_subdirectory(stdlib)
add_subdirectory(vm)
add_subdirectory(extensionsystem)
add_subdirectory(dataformats)
add_subdirectory(errormessages)
......
project(VM)
cmake_minimum_required(VERSION 3.0)
find_package(Kumir2 REQUIRED)
set(SOURCES
kumirstdlib.cpp
)
kumir2_add_library(
NAME Stdlib
SOURCES ${SOURCES}
)
#include "kumirstdlib.hpp"
namespace Kumir
{
String Core::error = String();
void (*Core::AbortHandler)() = 0;
std::deque<FileType> Files::openedFiles;
AbstractInputBuffer *Files::consoleInputBuffer = 0;
AbstractOutputBuffer *Files::consoleOutputBuffer = 0;
AbstractOutputBuffer *Files::consoleErrorBuffer = 0;
FILE *Files::assignedIN = stdin;
FILE *Files::assignedOUT = stdout;
#if defined(WIN32) || defined(_WIN32)
Encoding IO::LOCALE_ENCODING = CP866;
#else
Encoding IO::LOCALE_ENCODING = UTF8;
#endif
Encoding Files::fileEncoding;
String Kumir::IO::inputDelimeters = Kumir::Core::fromAscii(" \n\t");
} // namespace Kumir
This diff is collapsed.
project(VM)
cmake_minimum_required(VERSION 3.0)
find_package(Kumir2 REQUIRED)
set(SOURCES
vm_instruction.cpp
vm_tableelem.cpp
vm_bytecode.cpp
vm_breakpoints_table.cpp
vm_console_handlers.cpp
variant.cpp
vm.cpp
)
kumir2_add_library(
NAME VM
SOURCES ${SOURCES}
LIBRARIES Stdlib
)
......@@ -6,26 +6,23 @@
#include "vm_instruction.hpp"
#include "vm_tableelem.hpp"
namespace VM {
namespace VM
{
enum ContextRunMode {
CRM_UntilReturn,
CRM_ToEnd,
CRM_OneStep
CRM_UntilReturn,
CRM_ToEnd,
CRM_OneStep
};
// Two strings
typedef std::pair<String,String> TwoStrings;
struct ExternReference {
int moduleContext;
uint32_t funcKey;
std::string moduleAsciiName;
String moduleLocalizedName;
bool platformDependent;
String fileName;
std::string platformModuleName;
int moduleContext;
uint32_t funcKey;
std::string moduleAsciiName;
String moduleLocalizedName;
bool platformDependent;
String fileName;
std::string platformModuleName;
};
typedef std::map<uint32_t, ExternReference> ExternsMap;
......@@ -45,44 +42,46 @@ typedef std::vector<Variable> VariantArray;
typedef std::map<uint32_t, VariantArray> LocalsMap;
struct Context {
inline Context() {
IP = -1; type = Bytecode::EL_FUNCTION;
runMode = CRM_ToEnd; lineNo = -1;
algId = -1;
program = 0;
moduleContextNo = 0;
columnStart = columnEnd = 0u;
}
VM::AnyValue registers[255];
int IP;
std::vector<Variable> locals;
const std::vector<Bytecode::Instruction> * program;
Bytecode::ElemType type;
ContextRunMode runMode;
uint8_t moduleId;
int algId;
int lineNo;
uint32_t columnStart;
uint32_t columnEnd;
size_t moduleContextNo;
Kumir::String name;
Context()
{
IP = -1;
type = Bytecode::EL_FUNCTION;
runMode = CRM_ToEnd;
lineNo = -1;
algId = -1;
program = 0;
moduleContextNo = 0;
columnStart = columnEnd = 0u;
}
VM::AnyValue registers[255];
int IP;
std::vector<Variable> locals;
const std::vector<Bytecode::Instruction> *program;
Bytecode::ElemType type;
ContextRunMode runMode;
uint8_t moduleId;
int algId;
int lineNo;
uint32_t columnStart;
uint32_t columnEnd;
size_t moduleContextNo;
Kumir::String name;
};
struct ModuleContext {
Kumir::String filename;
FunctionMap functions;
ExternsMap externs;
std::list<ExternReference> externInits;
std::deque<Bytecode::TableElem> inits;
LocalsMap cleanLocalTables;
GlobalsMap globals;
std::vector<Kumir::String> moduleNames;
ConstantsMap constants;
uint8_t exportModuleId;
Kumir::String filename;
FunctionMap functions;
ExternsMap externs;
std::list<ExternReference> externInits;
std::deque<Bytecode::TableElem> inits;
LocalsMap cleanLocalTables;
GlobalsMap globals;
std::vector<Kumir::String> moduleNames;
ConstantsMap constants;
uint8_t exportModuleId;
};
}
#endif
......@@ -4,71 +4,80 @@
#include <cstdlib>
#include <vector>
namespace VM {
namespace VM
{
template <class T> class Stack
{
public:
inline void push(const T& t)
{
currentIndex_ ++;
if (currentIndex_>=(int)data_.size()) {
data_.resize(data_.size()+deltaSize_);
}
data_[currentIndex_] = t;
}
inline T pop()
{
currentIndex_--;
return data_[currentIndex_+1];
}
inline T& top()
{
return data_[currentIndex_];
}
inline const T& top() const
{
return data_[currentIndex_];
}
inline T& at(int index)
{
return data_[index];
}
inline const T& at(int index) const
{
return data_[index];
}
inline int size() const { return currentIndex_+1; }
inline int reservedSize() const { return data_.size(); }
inline void reset()
{
data_ = std::vector<T>(initialSize_);
currentIndex_ = -1;
}
inline ~Stack()
{
data_.clear();
}
void push(const T &t)
{
currentIndex_ ++;
if (currentIndex_ >= (int)data_.size()) {
data_.resize(data_.size() + deltaSize_);
}
data_[currentIndex_] = t;
}
T pop()
{
currentIndex_--;
return data_[currentIndex_ + 1];
}
T &top()
{
return data_[currentIndex_];
}
const T &top() const
{
return data_[currentIndex_];
}
T &at(int index)
{
return data_[index];
}
const T &at(int index) const
{
return data_[index];
}
int size() const
{
return currentIndex_ + 1;
}
int reservedSize() const
{
return data_.size();
}
void reset()
{
data_ = std::vector<T>(initialSize_);
currentIndex_ = -1;
}
Stack()
{
initialSize_ = deltaSize_ = 100;
currentIndex_ = 0;
data_ = std::vector<T>(100);
}
~Stack()
{
data_.clear();
}
private:
int initialSize_;
int deltaSize_;
int currentIndex_;
std::vector<T> data_;
public:
inline Stack() {
initialSize_ = deltaSize_ = 100;
currentIndex_ = 0;
data_ = std::vector<T>(100);
}
int initialSize_;
int deltaSize_;
int currentIndex_;
std::vector<T> data_;
};
}
......
#include "variant.hpp"
namespace VM
{
bool Variable::hasValue() const
{
if (reference_) {
if (referenceIndeces_[3] == 0) {
return reference_->hasValue();
} else if (referenceIndeces_[3] == 1) {
return reference_->hasValue(referenceIndeces_[0]);
} else if (referenceIndeces_[3] == 2) {
return reference_->hasValue(referenceIndeces_[0], referenceIndeces_[1]);
} else {
return reference_->hasValue(referenceIndeces_[0], referenceIndeces_[1], referenceIndeces_[2]);
}
} else {
return value_.isValid();
}
}
bool Variable::hasValue(int indeces[4]) const
{
if (indeces[3] == 1) {
return hasValue(indeces[0]);
} else if (indeces[3] == 2) {
return hasValue(indeces[0], indeces[1]);
} else if (indeces[3] == 3) {
return hasValue(indeces[0], indeces[1], indeces[2]);
} else {
return hasValue();
}
}
AnyValue Variable::value() const
{
if (reference_) {
if (referenceIndeces_[3] == 0) {
return reference_->value();
} else if (referenceIndeces_[3] == 1) {
return reference_->value(referenceIndeces_[0]);
} else if (referenceIndeces_[3] == 2) {
return reference_->value(referenceIndeces_[0], referenceIndeces_[1]);
} else if (referenceIndeces_[3] == 3) {
return reference_->value(referenceIndeces_[0], referenceIndeces_[1], referenceIndeces_[2]);
}
} else {
if (!value_.isValid() && !ignoreUndefinedError) {
Kumir::Core::abort(Kumir::Core::fromUtf8("Нет значения у величины"));
}
return value_;
}
return value_;
}
void Variable::setValue(const AnyValue &v)
{
if (reference_) {
if (referenceIndeces_[3] == 0) {
reference_->setValue(v);
} else if (referenceIndeces_[3] == 1) {
reference_->setValue(referenceIndeces_[0], v);
} else if (referenceIndeces_[3] == 2) {
reference_->setValue(referenceIndeces_[0], referenceIndeces_[1], v);
} else if (referenceIndeces_[3] == 3) {
reference_->setValue(referenceIndeces_[0], referenceIndeces_[1], referenceIndeces_[2], v);
}
} else {
value_ = v;
}
}
String Variable::toString() const
{
String result;
switch (baseType_) {
case VT_bool:
if (value().toBool()) {
result = Kumir::Core::fromUtf8("да");
} else {
result = Kumir::Core::fromUtf8("нет");
}
break;
case VT_real:
result = Kumir::Converter::sprintfReal(value().toReal(), '.', false, 0, -1, 0);
break;
case VT_int:
result = Kumir::Converter::sprintfInt(value().toInt(), 10, 0, 0);
break;
case VT_char:
result.push_back(value().toChar());
break;
case VT_string:
result = value().toString();
break;
default:
break;
}
return result;
}
String Variable::toString(int indeces[4]) const
{
String result;
switch (baseType_) {
case VT_bool:
if (value(indeces).toBool()) {
result = Kumir::Core::fromUtf8("да");
} else {
result = Kumir::Core::fromUtf8("нет");
}
break;
case VT_real:
result = Kumir::Converter::sprintfReal(value(indeces).toReal(), '.', false, 0, -1, 0);
break;
case VT_int:
result = Kumir::Converter::sprintfInt(value(indeces).toInt(), 10, 0, 0);
break;
case VT_char:
result.push_back(value(indeces).toChar());
break;
case VT_string:
result = value(indeces).toString();
break;
default:
break;
}
return result;
}
AnyValue Variable::value(int indeces[4]) const
{
if (indeces[3] == 1) {
return value(indeces[0]);
} else if (indeces[3] == 2) {
return value(indeces[0], indeces[1]);
} else if (indeces[3] == 3) {
return value(indeces[0], indeces[1], indeces[2]);
} else {
return value();
}
}
void Variable::setValue(int indeces[4], const AnyValue &value)
{
if (indeces[3] == 1) {
setValue(indeces[0], value);
} else if (indeces[3] == 2) {
setValue(indeces[0], indeces[1], value);
} else if (indeces[3] == 3) {
setValue(indeces[0], indeces[1], indeces[2], value);
} else {
setValue(value);
}
}
size_t Variable::linearIndex(int a) const
{
return a - bounds_[0];
}
size_t Variable::linearIndex(int a, int b) const
{
int size0 = bounds_[3] - bounds_[2] + 1;
int offset0 = (a - bounds_[0]) * size0;
int result = offset0 + b - bounds_[2];
return result;
}
size_t Variable::linearIndex(int a, int b, int c) const
{
int size0 = bounds_[3] - bounds_[2] + 1;
int size1 = bounds_[5] - bounds_[4] + 1;
return (a - bounds_[0]) * size0 * size1 + (b - bounds_[2]) * size1 + c - bounds_[4];
}
void Variable::setConstValue(const Variable &ctab)
{
if (isReference()) {
reference_->setConstValue(ctab);
return;
}
const int dim = ctab.dimension();
int cbounds[7];
if (dim > 0) {
ctab.getBounds(cbounds);
for (int i = 0; i < dim; i++) {
const int mysize = bounds_[2 * i + 1] - bounds_[2 * i];
const int csize = cbounds [2 * i + 1] - cbounds [2 * i];
if (mysize < csize) {
Kumir::Core::abort(Kumir::Core::fromUtf8("Выход за границу таблицы"));
return;
}
}
}
switch (dim) {
case 0: {
setValue(ctab.value());
break;
}
case 1: {
const int cx = cbounds [0];
const int mx = bounds_[0];
const int sx = cbounds [1] - cbounds [0];
for (int x = 0; x <= sx; x++) {
setValue(mx + x, ctab.value(cx + x));
}
break;
}
case 2: {
const int cy = cbounds [0];
const int my = bounds_[0];
const int cx = cbounds [2];
const int mx = bounds_[2];
const int sy = cbounds [1] - cbounds [0];
const int sx = cbounds [3] - cbounds [2];
for (int y = 0; y <= sy; y++) {
for (int x = 0; x <= sx; x++) {
setValue(my + y, mx + x, ctab.value(cy + y, cx + x));
unsetError();
}
}
break;
}
case 3: {
const int cz = cbounds [0];
const int mz = bounds_[0];
const int cy = cbounds [2];
const int my = bounds_[2];
const int cx = cbounds [4];
const int mx = bounds_[4];
const int sz = cbounds [1] - cbounds [0];
const int sy = cbounds [3] - cbounds [2];
const int sx = cbounds [5] - cbounds [4];
for (int z = 0; z < sz; z++) {
for (int y = 0; y <= sy; y++) {
for (int x = 0; x <= sx; x++) {
setValue(mz + z, my + y, mx + x, ctab.value(cz + z, cy + y, cx + x));
}
}
}
break;
}
default: {
break;
}
}
}
// DIM = 1
bool Variable::hasValue(int index0) const
{
if (reference_) {
return reference_->hasValue(index0);
}
if (value_.rawSize() == 0 || restrictedBounds_[6] < 1) {
return false;
}
if (index0 < restrictedBounds_[0] || index0 > restrictedBounds_[1]) {
return false;
}
int index = linearIndex(index0);