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 }