github.com/igggame/nebulas-go@v2.1.0+incompatible/nf/nvm/v8/samples/main.cc (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see
    17  // <http://www.gnu.org/licenses/>.
    18  //
    19  #include <unistd.h>
    20  #include "../engine.h"
    21  #include "../lib/blockchain.h"
    22  #include "../lib/fake_blockchain.h"
    23  #include "../lib/file.h"
    24  #include "../lib/log_callback.h"
    25  #include "../lib/logger.h"
    26  #include "memory_modules.h"
    27  #include "memory_storage.h"
    28  
    29  #include <thread>
    30  #include <vector>
    31  
    32  #include <errno.h>
    33  #include <stdio.h>
    34  #include <stdlib.h>
    35  #include <string.h>
    36  
    37  static int concurrency = 1;
    38  static int enable_tracer_injection = 0;
    39  static int strict_disallow_usage = 0;
    40  static size_t limits_of_executed_instructions = 0;
    41  static size_t limits_of_total_memory_size = 0;
    42  static int print_injection_result = 0;
    43  
    44  void logFunc(int level, const char *msg) {
    45    std::thread::id tid = std::this_thread::get_id();
    46    std::hash<std::thread::id> hasher;
    47  
    48    FILE *f = stdout;
    49    if (level >= LogLevel::ERROR) {
    50      f = stderr;
    51    }
    52    fprintf(f, "[tid-%020zu] [%s] %s\n", hasher(tid), GetLogLevelText(level),
    53            msg);
    54  }
    55  
    56  void eventTriggerFunc(void *handler, const char *topic, const char *data,
    57                        size_t *cnt) {
    58    fprintf(stdout, "[Event] [%s] %s\n", topic, data);
    59    *cnt = 20 + strlen(topic) + strlen(data);
    60  }
    61  
    62  void help(const char *name) {
    63    printf("%s [-c <concurrency>] [-i] [-li <number>] [-lm <number>] <Javascript "
    64           "File>\n",
    65           name);
    66    printf("\t -c <concurrency> \tNumber of multiple thread to run at a time.\n");
    67    printf("\t -i \tinject tracing code.\n");
    68    printf("\t -is \tstrict disallow usage of _instruction_counter..\n");
    69    printf("\t -li <number> \tlimits of executed instructions, default is 0 "
    70           "(unlimited).\n");
    71    printf("\t -im <number> \tlimits of total heap size, default is 0 "
    72           "(unlimited).\n");
    73    printf("\n");
    74  
    75    printf("%s -ip <Javascript File>\n", name);
    76    printf("\t -ip \tinject tracing code and print result\n");
    77    printf("\t -is \tstrict disallow usage of _instruction_counter..\n");
    78  
    79    printf("\n");
    80    exit(1);
    81  }
    82  
    83  typedef void (*V8ExecutionDelegate)(V8Engine *e, const char *data,
    84                                      uintptr_t lcsHandler, uintptr_t gcsHandler);
    85  
    86  void RunScriptSourceDelegate(V8Engine *e, const char *data,
    87                               uintptr_t lcsHandler, uintptr_t gcsHandler) {
    88    int lineOffset = 0;
    89  
    90    if (enable_tracer_injection) {
    91      e->limits_of_executed_instructions = limits_of_executed_instructions;
    92      e->limits_of_total_memory_size = limits_of_total_memory_size;
    93  
    94      char *traceableSource =
    95          InjectTracingInstructions(e, data, &lineOffset, strict_disallow_usage);
    96      if (traceableSource == NULL) {
    97        fprintf(stderr, "Inject tracing instructions failed.\n");
    98      } else {
    99        char *out = NULL;
   100        int ret = RunScriptSource(&out, e, traceableSource, lineOffset,
   101                                  (uintptr_t)lcsHandler, (uintptr_t)gcsHandler);
   102        free(traceableSource);
   103  
   104        fprintf(stdout, "[V8] Execution ret = %d, out = %s\n", ret, out);
   105        free(out);
   106  
   107        ret = IsEngineLimitsExceeded(e);
   108        if (ret) {
   109          fprintf(stdout, "[V8Error] Exceed %s limits, ret = %d\n",
   110                  ret == 1 ? "Instructions" : "Memory", ret);
   111        }
   112  
   113        // print tracing stats.
   114        fprintf(stdout,
   115                "\nStats of V8Engine:\n"
   116                "  count_of_executed_instructions: \t%zu\n"
   117                "  total_memory_size: \t\t\t%zu\n"
   118                "  total_heap_size: \t\t\t%zu\n"
   119                "  total_heap_size_executable: \t\t%zu\n"
   120                "  total_physical_size: \t\t\t%zu\n"
   121                "  total_available_size: \t\t%zu\n"
   122                "  used_heap_size: \t\t\t%zu\n"
   123                "  heap_size_limit: \t\t\t%zu\n"
   124                "  malloced_memory: \t\t\t%zu\n"
   125                "  peak_malloced_memory: \t\t%zu\n"
   126                "  total_array_buffer_size: \t\t%zu\n"
   127                "  peak_array_buffer_size: \t\t%zu\n",
   128                e->stats.count_of_executed_instructions,
   129                e->stats.total_memory_size, e->stats.total_heap_size,
   130                e->stats.total_heap_size_executable, e->stats.total_physical_size,
   131                e->stats.total_available_size, e->stats.used_heap_size,
   132                e->stats.heap_size_limit, e->stats.malloced_memory,
   133                e->stats.peak_malloced_memory, e->stats.total_array_buffer_size,
   134                e->stats.peak_array_buffer_size);
   135      }
   136    } else {
   137      char *out = NULL;
   138      int ret = RunScriptSource(&out, e, data, lineOffset, (uintptr_t)lcsHandler,
   139                                (uintptr_t)gcsHandler);
   140      fprintf(stdout, "[V8] Execution ret = %d, out = %s\n", ret, out);
   141      free(out);
   142    }
   143  }
   144  
   145  void InjectTracingInstructionsAndPrintDelegate(V8Engine *e, const char *data,
   146                                                 uintptr_t lcsHandler,
   147                                                 uintptr_t gcsHandler) {
   148    const char *begin = strstr(data, "\"") + 1;
   149    const char *end = strstr(begin, "\"");
   150  
   151    char id[128];
   152    int idx = 0;
   153    while (begin + idx != end) {
   154      id[idx] = begin[idx];
   155      idx++;
   156    }
   157    id[idx] = '\0';
   158  
   159    char *source = GetModuleSource(e, id);
   160    fprintf(stdout, "%s", source);
   161    free(source);
   162  }
   163  
   164  void ExecuteScript(const char *filename, V8ExecutionDelegate delegate) {
   165    void *lcsHandler = CreateStorageHandler();
   166    void *gcsHandler = CreateStorageHandler();
   167  
   168    V8Engine *e = CreateEngine();
   169  
   170    size_t size = 0;
   171    int lineOffset = 0;
   172    char *source = readFile(filename, &size);
   173    if (source == NULL) {
   174      fprintf(stderr, "%s is not found.\n", filename);
   175      exit(1);
   176    }
   177  
   178    // convert TS to js if needed.
   179    size_t filenameLen = strlen(filename);
   180    if (filenameLen > 3 && filename[filenameLen - 3] == '.' &&
   181        filename[filenameLen - 2] == 't' && filename[filenameLen - 1] == 's') {
   182      size = 0;
   183      char *jsSource = TranspileTypeScriptModule(e, source, &lineOffset);
   184      if (jsSource == NULL) {
   185        fprintf(stderr, "%s is not a valid TypeScript file.\n", filename);
   186        free(source);
   187        exit(1);
   188      }
   189      free(source);
   190      source = jsSource;
   191    }
   192  
   193    // inject tracing code.
   194    if (enable_tracer_injection) {
   195      char *traceableSource = InjectTracingInstructions(e, source, &lineOffset,
   196                                                        strict_disallow_usage);
   197      if (traceableSource == NULL) {
   198        fprintf(stderr, "Inject tracing instructions failed.\n");
   199        free(source);
   200        return;
   201      }
   202      free(source);
   203      source = traceableSource;
   204    }
   205  
   206    char id[128];
   207    sprintf(id, "./%s", filename);
   208  
   209    AddModule(e, id, source, lineOffset);
   210  
   211    char data[128];
   212    sprintf(data, "require(\"%s\");", id);
   213  
   214    delegate(e, data, (uintptr_t)lcsHandler, (uintptr_t)gcsHandler);
   215  
   216    free(source);
   217    DeleteEngine(e);
   218  
   219    DeleteStorageHandler(lcsHandler);
   220    DeleteStorageHandler(gcsHandler);
   221  }
   222  void *loop(void *arg) {
   223  
   224    ExecuteScript((const char*)arg, RunScriptSourceDelegate);
   225    return 0x00;
   226  }
   227  void ExecuteScriptSource(const char *filename) {
   228      ExecuteScript(filename, RunScriptSourceDelegate);
   229  }
   230  
   231  int main(int argc, const char *argv[]) {
   232    if (argc < 2) {
   233      help(argv[0]);
   234    }
   235  
   236    Initialize();
   237    InitializeLogger(logFunc);
   238    InitializeRequireDelegate(RequireDelegateFunc, AttachLibVersionDelegateFunc);
   239    InitializeExecutionEnvDelegate(AttachLibVersionDelegateFunc);
   240    InitializeStorage(StorageGet, StoragePut, StorageDel);
   241    InitializeBlockchain(GetTxByHash, GetAccountState, Transfer, VerifyAddress, GetPreBlockHash, GetPreBlockSeed, NULL, NULL, GetLatestNebulasRank, GetLatestNebulasRankSummary);
   242    InitializeEvent(eventTriggerFunc);
   243  
   244    int argcIdx = 1;
   245    const char *filename = NULL;
   246  
   247    for (;;) {
   248      const char *arg = argv[argcIdx];
   249      if (strcmp(arg, "-c") == 0) {
   250        argcIdx++;
   251        concurrency = atoi(argv[argcIdx]);
   252        argcIdx++;
   253        if (concurrency <= 0) {
   254          fprintf(stderr, "concurrency can't less than 0, set to 1.\n");
   255          concurrency = 1;
   256        }
   257      } else if (strcmp(arg, "-i") == 0) {
   258        argcIdx++;
   259        enable_tracer_injection = 1;
   260      } else if (strcmp(arg, "-is") == 0) {
   261        argcIdx++;
   262        strict_disallow_usage = 1;
   263      } else if (strcmp(arg, "-li") == 0) {
   264        argcIdx++;
   265  
   266        char *s = NULL;
   267        long limits = strtol(argv[argcIdx], &s, 10);
   268        argcIdx++;
   269  
   270        if (errno == EINVAL) {
   271          continue;
   272        }
   273  
   274        if (errno == ERANGE) {
   275          // do nothing.
   276          limits_of_executed_instructions = 0;
   277        } else {
   278          limits_of_executed_instructions = limits;
   279        }
   280      } else if (strcmp(arg, "-lm") == 0) {
   281        argcIdx++;
   282  
   283        char *s = NULL;
   284        long limits = strtol(argv[argcIdx], &s, 10);
   285        argcIdx++;
   286  
   287        if (errno == EINVAL) {
   288          continue;
   289        }
   290  
   291        if (errno == ERANGE) {
   292          // do nothing.
   293          limits_of_total_memory_size = 0;
   294        } else {
   295          limits_of_total_memory_size = limits;
   296        }
   297      } else if (strcmp(arg, "-ip") == 0) {
   298        argcIdx++;
   299        print_injection_result = 1;
   300        enable_tracer_injection = 1;
   301      } else {
   302        filename = arg;
   303        break;
   304      }
   305    }
   306  
   307    if (print_injection_result) {
   308      // inject and print.
   309      ExecuteScript(filename, InjectTracingInstructionsAndPrintDelegate);
   310    } else {
   311      pthread_attr_t attribute;
   312      std::vector<pthread_t > threads;
   313      for (int i = 0; i < concurrency; i++) {
   314        pthread_t thread;
   315        pthread_attr_init(&attribute);
   316        pthread_attr_setstacksize(&attribute, 2 * 1024 * 1024);
   317  
   318        pthread_create(&thread,&attribute, loop, (void *)filename);
   319        threads.push_back(thread);
   320      }
   321      for (int i = 0; i < concurrency; i++) {
   322        pthread_join(threads[i], 0);
   323      }
   324      printf("success\n");
   325    }
   326  
   327    Dispose();
   328    return 0;
   329  }