LCOV - code coverage report
Current view: top level - src/runtime - vmachine.cpp (source / functions) Hit Total Coverage
Test: flower-f.info Lines: 265 293 90.4 %
Date: 2022-06-10 00:44:15 Functions: 38 60 63.3 %

          Line data    Source code
       1             : #include <iostream>
       2             : #include <cstring>
       3             : #include <unistd.h>
       4             : #include <signal.h>
       5             : #include <sys/wait.h>
       6             : #include <sys/types.h>
       7             : #include <sys/stat.h>
       8             : #include <fcntl.h>
       9             : #include "runtime/vmachine.hpp"
      10             : #include "common/exprtype.hpp"
      11             : #include "common/obstacle.hpp"
      12             : 
      13          52 : void VirtualMachine::loadBIN(const char * filename) {
      14          52 :     std::ifstream bin;
      15          52 :     bin.open(filename, std::ios_base::binary | std::ios_base::in);
      16             : 
      17          52 :     bin.seekg(0, std::ios::end);
      18          52 :     int size = bin.tellg();
      19          52 :     base = new char [size];
      20          52 :     bin.seekg(0, std::ios::beg);
      21          52 :     bin.read(base, size * sizeof(char));
      22             : 
      23          52 :     cmd = base + *reinterpret_cast<int*>(base);
      24          52 :     bin.close();
      25          52 :     cmdNum = (size - *reinterpret_cast<int*>(base)) / (sizeof(int) + sizeof(bool));
      26          52 : }
      27             : 
      28          52 : void VirtualMachine::run(void) {
      29             :     op_t op;
      30          52 :     int * eip = new int (0);
      31          52 :     std::cout << std::boolalpha;
      32             : 
      33             :     while (true) {
      34        6876 :         if (*reinterpret_cast<bool*>(cmd + 4 + *eip * 5)) { // ExecBit = 1
      35        3352 :             op = (op_t) *reinterpret_cast<int *>(cmd + *eip * 5);
      36        3352 :             if (exec(op, eip)) break;
      37             :         } else { // ExecBit = 0
      38        3524 :             int shift = * reinterpret_cast<int *>(cmd + *eip * 5);
      39        3524 :             stackVM.push(static_cast<void *>(base + shift));
      40             :         }
      41        6824 :         *eip += 1;
      42        6824 :     }
      43             : 
      44          52 :     if (inThread) {
      45           4 :         void * nullp = nullptr;
      46           4 :         write(pipefd.back()[1], &nullp, sizeof(void*));
      47             :         #ifdef DEBUG
      48             :         std::cout << "Передал отцовскому процессу нуль." << std::endl;
      49             :         #endif
      50             :     }
      51             : 
      52             :     #ifdef DEBUG
      53             :     std::cout << "Машина завершила свою работу." << std::endl;
      54             :     #endif
      55             : 
      56          58 :     while (pipefd.size() != 0) {
      57           6 :         delete[] pipefd.back();
      58           6 :         pipefd.pop_back();
      59             :     }
      60             : 
      61          52 :     delete eip;
      62          52 : }
      63             : 
      64             : template <class lval_t, class rval_t, class res_t>
      65         829 : void VirtualMachine::tempOp(res_t (*f) (lval_t, rval_t), type_t TYPE) {
      66         829 :     rval_t b = * static_cast<rval_t *>(stackVM.pop());
      67         829 :     lval_t a = * static_cast<lval_t *>(stackVM.pop());
      68         829 :     stackVM.push(new res_t ( f(a, b) ), TYPE);
      69         829 : }
      70             : 
      71             : template <class lval_t, class rval_t>
      72         388 : void VirtualMachine::assign(void) {
      73         388 :     if (inThread) {
      74          48 :         rval_t x = * static_cast<rval_t *>(stackVM.pop());
      75          48 :         lval_t * p = static_cast<lval_t *>(stackVM.pop());
      76          48 :         *p = x;
      77          48 :         int n = sizeof(rval_t);
      78          48 :         write(pipefd.back()[1], &p, sizeof(void*));
      79          48 :         write(pipefd.back()[1], &n, sizeof(int));
      80          48 :         write(pipefd.back()[1], &x, sizeof(rval_t));
      81             :     } else {
      82         340 :         rval_t x = * static_cast<rval_t *>(stackVM.pop());
      83         340 :         * static_cast<lval_t *>(stackVM.pop()) = x;
      84             :     }
      85         388 : }
      86             : 
      87         381 : char * VirtualMachine::getString(void * x) {
      88         381 :     return (static_cast<char **>( x )[0] == nullptr)
      89         381 :                 ? static_cast<char *>( x ) + sizeof(char*)
      90         381 :                 : * static_cast<char**>( x );
      91             : }
      92             : 
      93        3352 : bool VirtualMachine::exec(op_t op, int * eip) {
      94        3352 :     bool exitStatus = false;
      95        3352 :     type_t rest = (type_t) ((op >> 24) & 0xFF);
      96        3352 :     type_t lval = (type_t) ((op >> 16) & 0xFF);
      97        3352 :     type_t rval = (type_t) ((op >>  8) & 0xFF);
      98             : 
      99        3352 :     if ((lval == _STRUCT_) || (rval == _STRUCT_))
     100           0 :         throw Obstacle(PANIC);
     101             : 
     102        3352 :     switch(op & 0xFF) {
     103         239 :         case PLUS:
     104         239 :             if (rest == _STRING_){
     105          13 :                 char * b = getString(stackVM.pop());
     106          13 :                 char * a = getString(stackVM.pop());
     107             : 
     108          13 :                 int alen = 0;
     109          13 :                 int blen = 0;
     110         132 :                 for (; a[alen] != '\0'; ++alen) {}
     111          61 :                 for (; b[blen] != '\0'; ++blen) {}
     112             : 
     113          13 :                 char * c = new char [alen + blen + 1 + sizeof(char*)];
     114          13 :                 memcpy(c, "\0\0\0\0\0\0\0\0", sizeof(char*));
     115          13 :                 memcpy(c + sizeof(char*), a, alen);
     116          13 :                 memcpy(c + alen + sizeof(char*), b, blen);
     117          13 :                 c[alen + blen + sizeof(char*)] = '\0';
     118          13 :                 stackVM.push(c);
     119          13 :                 dynamicStrings.push(c, _STRING_);
     120             :             } else {
     121         452 :                 ARITH_OPERATION(+)
     122             :             }
     123         239 :             break;
     124         144 :         case MINUS: ARITH_OPERATION(-) break;
     125         288 :         case MUL:   ARITH_OPERATION(*) break;
     126         208 :         case DIV:   ARITH_OPERATION(/) break;
     127          12 :         case MOD: {
     128          12 :             int b = * static_cast<int *>(stackVM.pop());
     129          12 :             int a = * static_cast<int *>(stackVM.pop());
     130          12 :             stackVM.push(new int (a % b), _INT_);
     131          12 :             break;
     132             :         }
     133           0 :         case INV:
     134           0 :             if (rest == _INT_) {
     135           0 :                 int a = * static_cast<int *>(stackVM.pop());
     136           0 :                 stackVM.push(new int (-a), _INT_);
     137             :             } else {
     138           0 :                 float a = * static_cast<float *>(stackVM.pop());
     139           0 :                 stackVM.push(new float (-a), _REAL_);
     140             :             }
     141           0 :             break;
     142         221 :         case LOAD: {
     143         221 :             int x = * static_cast<int *>(stackVM.pop());
     144         221 :             void * shv = sharedVars.get(x);
     145         221 :             void * a = registerVM.get(x);
     146         221 :             stackVM.push(shv == nullptr? a : shv);
     147         221 :             break;
     148             :         }
     149         402 :         case ASSIGN:
     150         402 :             if (lval == _INT_) {
     151         274 :                 if (rval == _INT_) assign<int, int>();
     152           6 :                 else assign<int, float>();
     153         128 :             } else if (lval == _REAL_) {
     154         102 :                 if (rval == _INT_) assign<float, int>();
     155          99 :                 else assign<float, float>();
     156          26 :             } else if (lval == _STRING_){
     157          14 :                 char * b = getString(stackVM.pop());
     158          14 :                 char * a = static_cast<char *>(stackVM.pop());
     159          14 :                 memcpy(a, &b, sizeof(void*));
     160          12 :             } else if (lval == _BOOLEAN_) {
     161          12 :                 assign<bool, bool>();
     162           0 :             } else throw Obstacle(PANIC);
     163         402 :             break;
     164          52 :         case STOP:
     165          52 :             exitStatus = true;
     166          52 :             break;
     167         733 :         case WRITE:
     168         733 :             if (rval == _INT_) {
     169         378 :                 int x = * static_cast<int *>(stackVM.pop());
     170         378 :                 std::cout << x;
     171         355 :             } else if (rval == _REAL_) {
     172          20 :                 float x = * static_cast<float *>(stackVM.pop());
     173          20 :                 std::cout << x;
     174         335 :             } else if (rval == _STRING_) {
     175         319 :                 char * x = getString(stackVM.pop());
     176         319 :                 std::cout << x;
     177          16 :             } else if (rval == _BOOLEAN_) {
     178          16 :                 bool x = * static_cast<bool *>(stackVM.pop());
     179          16 :                 std::cout << x;
     180           0 :             } else throw Obstacle(PANIC);
     181         733 :             break;
     182         225 :         case ENDL:
     183         225 :             std::cout << std::endl;
     184         225 :             break;
     185         298 :         case JIT: {
     186         298 :             int offset = * static_cast<int *>(stackVM.pop());
     187         298 :             bool condition = * static_cast<bool *>(stackVM.pop());
     188         298 :             if (condition) *eip = offset - 1;
     189         298 :             break;
     190             :         }
     191         226 :         case JMP: {
     192         226 :             int offset = * static_cast<int *>(stackVM.pop());
     193         226 :             *eip = offset - 1;
     194         226 :             break;
     195             :         }
     196          34 :         case LESS:
     197          34 :             if ((lval == _STRING_) && (rval == _STRING_)) {
     198           5 :                 char * b = getString(stackVM.pop());
     199           5 :                 char * a = getString(stackVM.pop());
     200           5 :                 int i = 0;
     201          20 :                 for (; (a[i] != '\0') && (b[i] != '\0'); i++) {}
     202           5 :                 stackVM.push(new bool ((a[i] == '\0') && (b[i] != '\0')), _BOOLEAN_);
     203             :             } else {
     204          58 :                 LOGIC_OPERATION(<)
     205             :             }
     206          34 :             break;
     207          30 :         case GRTR:
     208          30 :             if ((lval == _STRING_) && (rval == _STRING_)) {
     209           0 :                 char * b = getString(stackVM.pop());
     210           0 :                 char * a = getString(stackVM.pop());
     211           0 :                 int i = 0;
     212           0 :                 for (; (a[i] != '\0') && (b[i] != '\0'); i++) {}
     213           0 :                 stackVM.push(new bool (b[i] == '\0'), _BOOLEAN_);
     214             :             } else {
     215          60 :                 LOGIC_OPERATION(>)
     216             :             }
     217          30 :             break;
     218         290 :         case LESSEQ: LOGIC_OPERATION(<=) break;
     219          12 :         case GRTREQ: LOGIC_OPERATION(>=) break;
     220          33 :         case EQ:
     221          33 :             if ((lval == _STRING_) && (rval == _STRING_)) {
     222           6 :                 char * b = getString(stackVM.pop());
     223           6 :                 char * a = getString(stackVM.pop());
     224           6 :                 bool r = true;
     225           6 :                 int i = 0;
     226          25 :                 for (; (a[i] != '\0') && (b[i] != '\0'); i++) {
     227          21 :                     if (a[i] != b[i]) {
     228           2 :                         r = false;
     229           2 :                         break;
     230             :                     }
     231             :                 }
     232           6 :                 r = r && (a[i] == '\0') && (b[i] == '\0');
     233           6 :                 stackVM.push(new bool (r), _BOOLEAN_);
     234             :             } else {
     235          54 :                 LOGIC_OPERATION(==)
     236             :             }
     237          33 :             break;
     238          46 :         case NEQ:
     239          46 :             if ((lval == _STRING_) && (rval == _STRING_)) {
     240           0 :                 char * b = getString(stackVM.pop());
     241           0 :                 char * a = getString(stackVM.pop());
     242           0 :                 bool r = true;
     243           0 :                 int i = 0;
     244           0 :                 for (; (a[i] != '\0') && (b[i] != '\0'); i++) {
     245           0 :                     if (a[i] != b[i]) {
     246           0 :                         r = false;
     247           0 :                         break;
     248             :                     }
     249             :                 }
     250           0 :                 r = r && (a[i] == '\0') && (b[i] == '\0');
     251           0 :                 stackVM.push(new bool (!r), _BOOLEAN_);
     252             :             } else {
     253          92 :                 LOGIC_OPERATION(!=)
     254             :             }
     255          46 :             break;
     256          59 :         case READ:
     257          59 :             if (rval == _INT_) {
     258             :                 float temp;
     259          39 :                 std::cin >> temp;
     260             : 
     261          39 :                 stackVM.updateType(_INT_);
     262          39 :                 * static_cast<int *>(stackVM.pop()) = (int)temp;
     263          20 :             } else if (rval == _REAL_) {
     264           8 :                 std::cin >> * static_cast<float *>(stackVM.pop());
     265          12 :             } else if (rval == _STRING_) {
     266          16 :                 std::string x;
     267           8 :                 std::cin >> x;
     268           8 :                 char * newString = new char[x.length() + 1];
     269           8 :                 memcpy(newString, x.data(), x.length() + 1);
     270           8 :                 char * a = static_cast<char *>(stackVM.pop());
     271           8 :                 const char * b = newString;
     272           8 :                 memcpy(a, &b, sizeof(void*));
     273           8 :                 dynamicStrings.push(newString, _STRING_);
     274             :             } else {
     275           4 :                 std::string x;
     276           4 :                 do { std::cin >> x; } 
     277           4 :                 while ((x != "True") && (x != "true") && (x != "False") && (x != "false"));
     278           4 :                 * static_cast<bool *>(stackVM.pop()) = (x == "True") || (x == "true");
     279             :             }
     280          59 :             break;
     281             : 
     282           4 :         case LAND: {
     283           4 :             bool b = * static_cast<bool *>(stackVM.pop());
     284           4 :             bool a = * static_cast<bool *>(stackVM.pop());
     285           4 :             stackVM.push(new bool (a && b), _BOOLEAN_);
     286           4 :             break;
     287             :         }
     288           5 :         case LOR: {
     289           5 :             bool b = * static_cast<bool *>(stackVM.pop());
     290           5 :             bool a = * static_cast<bool *>(stackVM.pop());
     291           5 :             stackVM.push(new bool (a || b), _BOOLEAN_);
     292           5 :             break;
     293             :         }
     294         110 :         case LNOT: {
     295         110 :             bool a = * static_cast<bool *>(stackVM.pop());
     296         110 :             stackVM.push(new bool (!a), _BOOLEAN_);
     297         110 :             break;
     298             :         }
     299          62 :         case CALL: {
     300          62 :             int offset = * static_cast<int *>(stackVM.pop());
     301          62 :             int param  = * static_cast<int *>(stackVM.pop());
     302         144 :             for (int i = 0; i < param; i++) {
     303          82 :                 registerVM.push( stackVM.pop() );
     304          82 :                 sharedVars.push(nullptr);
     305             :             }
     306          62 :             params.push(new int (param), _INT_);
     307          62 :             offsets.push(new int (*eip + 1), _INT_);
     308          62 :             *eip = offset - 1;
     309          62 :             break;
     310             :         }
     311          62 :         case RET: {
     312          62 :             int offset = * static_cast<int *>(offsets.pop());
     313          62 :             int param  = * static_cast<int *>(params.pop());
     314         144 :             while (param--) registerVM.pop();
     315          62 :             *eip = offset - 1;
     316          62 :             break;
     317             :         }
     318          13 :         case SHARE: {
     319          13 :             int x = * static_cast<int *>(stackVM.pop());
     320          13 :             sharedVars.set(x, registerVM.get(x));
     321          13 :             break;
     322             :         }
     323          10 :         case FORK: {
     324          10 :             pipefd.push_back(new int[2]);
     325          10 :             pipe(pipefd.back());
     326             : 
     327          10 :             pid_t pid = fork();
     328          10 :             threads.push_back(pid);
     329             : 
     330          10 :             if (pid == -1) throw Obstacle(PANIC);
     331          10 :             if (pid == 0) {
     332           4 :                 inThread = true;
     333           4 :                 int offset = * static_cast<int *>(stackVM.pop());
     334           4 :                 *eip = offset - 1;
     335             :             } 
     336             :             #ifdef DEBUG
     337             :             else {
     338             :                 std::cout << "Запущен новый поток с PID = " << pid << std::endl;
     339             :             }
     340             :             #endif
     341          10 :             break;
     342             :         }
     343           6 :         case LOCK: {
     344           6 :             while (threads.size() != 0) {
     345           4 :                 int st, ret = 0;
     346           4 :                 updateVars();
     347           4 :                 pid_t pid = threads.back();
     348           4 :                 ret = waitpid(pid, &st, 0);
     349           4 :                 if (ret == -1) throw Obstacle(PANIC);
     350           4 :                 else if (WIFEXITED(st)) threads.pop_back();
     351             :             }
     352           2 :             break;
     353             :         }
     354           3 :         case UNPACK: {
     355           3 :             int fieldSize = * static_cast<int *>(stackVM.pop());
     356          15 :             for (int i = 0; i < fieldSize * 2; i++) {
     357          12 :                 registerVM.push(stackVM.pop());
     358             :             }
     359           9 :             for (int i = 0; i < fieldSize; i++) {
     360           6 :                 stackVM.push(registerVM.get(i));
     361           6 :                 stackVM.push(registerVM.get(i + fieldSize));
     362             :             }
     363          15 :             for (int i = 0; i < fieldSize * 2; i++) {
     364          12 :                 registerVM.pop();
     365             :             }
     366           3 :             break;
     367             :         }
     368           0 :         default:
     369           0 :             std::cout << "Неизвестная команда." << std::endl;
     370           0 :             exit(-1);
     371             :     }
     372             : 
     373        3352 :     return exitStatus;
     374             : }
     375             : 
     376          56 : void VirtualMachine::updateVars(void) {
     377             :     void * p;
     378             :     int n;
     379          56 :     while (pipefd.size() != 0) {
     380          52 :         read(pipefd.back()[0], &p, sizeof(void *));
     381          52 :         if (p == nullptr) {
     382           4 :             delete[] pipefd.back();
     383           4 :             pipefd.pop_back();
     384           4 :             continue;
     385             :         }
     386          48 :         read(pipefd.back()[0], &n, sizeof(int));
     387          48 :         read(pipefd.back()[0], p, n);
     388             :     }
     389           4 : }
     390             : 
     391          52 : VirtualMachine::~VirtualMachine(void) {
     392          52 :     delete [] base;
     393          52 :     dynamicStrings.burn();
     394          52 : }

Generated by: LCOV version 1.14