1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. 3 * Description: Definition of source file for generating bytecode. 4 * Create: 2020/09/07 5 */ 6 7#ifdef JERRY_FOR_IAR_CONFIG 8 9#include "generate-bytecode.h" 10 11#include <string.h> 12 13#include "config-gt.h" 14#include "config-jupiter.h" 15 16#define VERSION_LEN 30 17#define ONETIME_MAX_OPTBYTES 4096 // max size for reading and writing at onetime 18 19// jerry version code 20char version_str[VERSION_LEN]; 21 22// secure functions 23extern int memset_s(void *dest, size_t destMax, int c, size_t count); 24extern int strcpy_s(char *strDest, size_t destMax, const char *strSrc); 25extern int strcat_s(char *strDest, size_t destMax, const char *strSrc); 26extern int strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); 27extern int sprintf_s(char *strDest, size_t destMax, const char *format, ...); 28extern int strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count); 29 30#ifdef JERRY_IAR_JUPITER 31extern uint8_t* input_buffer; 32extern uint8_t* snapshot_buffer; 33#endif // JERRY_IAR_JUPITER 34 35/** 36 * jerry snapshot format version 37 */ 38char* get_jerry_version_no() { 39 if (sprintf_s(version_str, sizeof(version_str), 40 "JERRY_SNAPSHOT_VERSION_%u", JERRY_SNAPSHOT_VERSION) < 0) { 41 return NULL; 42 } 43 return version_str; 44} /* get_jerry_version_no */ 45 46/** 47 * splice path and filename 48 */ 49char* splice_path(char* str1, char* str2) { 50 int len1 = strlen(str1); 51 int len2 = strlen(str2); 52 int res_len = len1 + len2 + 1; // str1 + "/" + str2 53 54 char* res = (char*)OhosMalloc(MEM_TYPE_JERRY, (res_len + 1) * sizeof(char)); 55 if (res == NULL) { 56 return NULL; 57 } 58 if (memset_s(res, res_len + 1, 0, res_len + 1) != 0) { 59 OhosFree(res); 60 res = NULL; 61 return NULL; 62 } 63 if (strcpy_s(res, len1 + 1, str1) != 0) { 64 OhosFree(res); 65 res = NULL; 66 return NULL; 67 } 68 if ((strcat_s(res, len1 + strlen("/") + 1, "/") != 0) 69 || (strcat_s(res, res_len + 1, str2) != 0)) { 70 OhosFree(res); 71 res = NULL; 72 return NULL; 73 } 74 return res; 75} /* splice_path */ 76 77/** 78 * judge if is template(js/bc) file 79 */ 80bool is_template_file(char* filename, char* template) { 81 const char* pFile; 82 pFile = strrchr(filename, '.'); 83 if ((pFile != NULL) && (strcmp(pFile, template) == 0)) { 84 return true; 85 } 86 return false; 87} /* is_template_file */ 88 89/** 90 * get output snapshot file absolutely path 91 */ 92char* get_output_file_path(char* input_file_path) { 93 int len = strlen(input_file_path); 94 char* output_file_path = (char*)OhosMalloc(MEM_TYPE_JERRY, (len + 1) * sizeof(char)); 95 if (output_file_path == NULL) { 96 return NULL; 97 } 98 if (memset_s(output_file_path, len + 1, 0, len + 1) != 0) { 99 OhosFree(output_file_path); 100 output_file_path = NULL; 101 return NULL; 102 } 103 if (strncpy_s(output_file_path, len, input_file_path, len - strlen(".js")) != 0) { 104 OhosFree(output_file_path); 105 output_file_path = NULL; 106 return NULL; 107 } 108 output_file_path[len-3] = '.'; 109 output_file_path[len-2] = 'b'; 110 output_file_path[len-1] = 'c'; 111 output_file_path[len] = '\0'; 112 return output_file_path; 113} /* get_output_file_path */ 114 115/** 116 * read js bundle file or snapshot file by Fragement 117 */ 118EXECRES read_js_or_snapshot_file(char* filename, uint8_t* target_file, int* file_bytesize, int buffer_capacity) { 119 int fd = 0; 120 struct stat file_stat = { 0 }; 121 int remain_to_read = 0; 122 int here_to_read = 0; 123 int tmp_read = 0; 124 int read_offset = 0; 125 fd = open(filename, O_RDONLY, S_IREAD); 126 if (fd < 0) { 127 // Error: failed to open file 128 return EXCE_ACE_JERRY_OPEN_FILE_FAILED; 129 } 130 if (fstat(fd, &file_stat) < 0) { 131 close(fd); 132 return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; 133 } 134 *file_bytesize = file_stat.st_size; 135 if (*file_bytesize > buffer_capacity) { 136 close(fd); 137 return EXCE_ACE_JERRY_FILE_TOO_LARGE; 138 } 139 remain_to_read = *file_bytesize; 140 while (remain_to_read > 0) { 141 here_to_read = (remain_to_read > ONETIME_MAX_OPTBYTES) ? 142 ONETIME_MAX_OPTBYTES : remain_to_read; 143 tmp_read = read(fd, target_file + read_offset, here_to_read); 144 if (tmp_read < 0 || tmp_read != here_to_read) { 145 close(fd); 146 // Error: failed to read file 147 return EXCE_ACE_JERRY_READ_FILE_FAILED; 148 } 149 read_offset = read_offset + here_to_read; 150 remain_to_read = remain_to_read - here_to_read; 151 } 152 if (read_offset != *file_bytesize) { 153 close(fd); 154 // Error: failed to successfully read file 155 return EXCE_ACE_JERRY_READ_FILE_FAILED; 156 } 157 close(fd); 158 return EXCE_ACE_JERRY_EXEC_OK; 159} /* read_js_or_snapshot_file */ 160 161/** 162 * write snapshot file by Fragment 163 */ 164EXECRES write_snapshot(char* output_file_name_path, size_t snapshot_size) { 165 int fd = 0; 166 int res = 0; 167 int remain_to_write = 0; 168 int here_to_write = 0; 169 int write_offset = 0; 170 171 fd = open(output_file_name_path, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); 172 if (fd < 0) { 173 // Error: Unable to open snapshot file 174 return EXCE_ACE_JERRY_OPEN_FILE_FAILED; 175 } 176 remain_to_write = snapshot_size; 177 while (remain_to_write > 0) { 178 here_to_write = (remain_to_write > ONETIME_MAX_OPTBYTES) ? 179 ONETIME_MAX_OPTBYTES : remain_to_write; 180 res = write(fd, snapshot_buffer + write_offset, here_to_write); 181 if (res <= 0 || res != here_to_write) { 182 close(fd); 183 // Error: Unable to write snapshot file 184 return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; 185 } 186 write_offset = write_offset + here_to_write; 187 remain_to_write = remain_to_write - here_to_write; 188 } 189 if (write_offset != snapshot_size) { 190 close(fd); 191 // Error: Unable to successfully write snapshot file 192 return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; 193 } 194 close(fd); 195 return EXCE_ACE_JERRY_EXEC_OK; 196} /* write_snapshot */ 197 198/** 199 * struct for Directory Node 200 */ 201typedef struct Node { 202 char* dir_name; 203 struct Node* next; 204} dir_node; 205 206/** 207 * free the memory for linkedlist 208 */ 209void free_link(dir_node* head) { 210 dir_node* tmp = NULL; 211 while (head != NULL) { 212 tmp = head; 213 head = head->next; 214 if (tmp->dir_name != NULL) { 215 OhosFree(tmp->dir_name); 216 tmp->dir_name = NULL; 217 } 218 OhosFree(tmp); 219 tmp = NULL; 220 } 221} /* free_link */ 222 223/** 224 * generate snapshot file 225 */ 226EXECRES generate_snapshot_file(char* input_file, char* output_file) { 227 uint8_t* target_Js = input_buffer; 228 jerry_value_t generate_result; 229 size_t snapshot_size = 0; 230 EXECRES write_res = EXCE_ACE_JERRY_EXEC_OK; 231 bool convert_state = false; 232 int file_bytesize = 0; 233 EXECRES read_res = EXCE_ACE_JERRY_EXEC_OK; 234 235 if (input_file == NULL || output_file == NULL) { 236 return EXCE_ACE_JERRY_NULL_PATH; 237 } 238 read_res = read_js_or_snapshot_file(input_file, target_Js, &file_bytesize, INPUTJS_BUFFER_SIZE); 239 if (read_res != EXCE_ACE_JERRY_EXEC_OK) { 240 return read_res; 241 } 242 243 generate_result = jerry_generate_snapshot ( 244 NULL, 245 0, 246 target_Js, 247 file_bytesize, 248 0, 249 (uint32_t* )snapshot_buffer, 250 SNAPSHOT_BUFFER_SIZE); 251 252 convert_state = jerry_value_is_error(generate_result) 253 || !jerry_value_is_number(generate_result); 254 if (convert_state) { 255 // Error: Generating snapshot failed 256 jerry_release_value(generate_result); 257 return EXCE_ACE_JERRY_GENERATE_SNAPSHOT_FAILED; 258 } 259 snapshot_size = (size_t)jerry_get_number_value(generate_result); 260 jerry_release_value(generate_result); 261 262 write_res = write_snapshot(output_file, snapshot_size); 263 if (write_res != EXCE_ACE_JERRY_EXEC_OK) { 264 // Error: Writing snapshot file failed 265 return write_res; 266 } 267 return EXCE_ACE_JERRY_EXEC_OK; 268}/* generate_snapshot_file */ 269 270/** 271 * init the linked list for files in filefolder. 272 */ 273EXECRES init_directory_list(char* filefolder, char* start_folder, dir_node **head, dir_node **end) { 274 struct stat file_stat = { 0 }; 275 int filefolder_len = strlen(filefolder) + 1; 276 if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { 277 return EXCE_ACE_JERRY_INPUT_PATH_ERROR; 278 } 279 if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { 280 return EXCE_ACE_JERRY_MALLOC_ERROR; 281 } 282 if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { 283 OhosFree(start_folder); 284 start_folder = NULL; 285 return EXCE_ACE_JERRY_INPUT_PATH_ERROR; 286 } 287 if ((*head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { 288 OhosFree(start_folder); 289 start_folder = NULL; 290 return EXCE_ACE_JERRY_LINKLIST_ERROR; 291 } 292 if ((*end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { 293 OhosFree(start_folder); 294 start_folder = NULL; 295 OhosFree(*head); 296 *head = NULL; 297 return EXCE_ACE_JERRY_LINKLIST_ERROR; 298 } 299 (*head)->dir_name = NULL; 300 (*head)->next = *end; 301 (*end)->dir_name = start_folder; 302 (*end)->next = NULL; 303 return EXCE_ACE_JERRY_EXEC_OK; 304} /* init_directory_list */ 305 306/** 307 * when visited node is a directory, add it to the node list's end. 308 */ 309EXECRES add_directory_to_pending_list(dir_node **end, char* input_file_path) { 310 dir_node *new_node = NULL; 311 if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { 312 OhosFree(input_file_path); 313 input_file_path = NULL; 314 return EXCE_ACE_JERRY_LINKLIST_ERROR; 315 } 316 // input_file_path for dir will be freed when that node is freed 317 new_node->dir_name = input_file_path; 318 new_node->next = NULL; 319 (*end)->next = new_node; 320 *end = new_node; 321 new_node = NULL; 322 return EXCE_ACE_JERRY_EXEC_OK; 323} /* add_directory_to_pending_list */ 324 325/** 326 * transform this js file into snapshot. 327 */ 328EXECRES gen_snapshot(char* input_file_path, char* output_file_path) { 329 RefreshAllServiceTimeStamp(); 330 jerry_init_flag_t flags = JERRY_INIT_EMPTY; 331 jerry_init (flags); 332 EXECRES generate_val = EXCE_ACE_JERRY_EXEC_OK; 333 generate_val = generate_snapshot_file(input_file_path, output_file_path); 334 jerry_cleanup(); 335 OhosFree(output_file_path); 336 output_file_path = NULL; 337 OhosFree(input_file_path); 338 input_file_path = NULL; 339 if (generate_val != EXCE_ACE_JERRY_EXEC_OK) { 340 return generate_val; // return error_code 341 } 342 return EXCE_ACE_JERRY_EXEC_OK; 343} /* gen_snapshot */ 344 345/** 346 * validate snapshot's version. 347 */ 348EXECRES validate_snapshot(char* input_file_path, char* output_file_path) { 349 uint8_t* snapshot_data_p = snapshot_buffer; 350 int file_bytesize = 0; 351 OhosFree(input_file_path); 352 input_file_path = NULL; 353 354 EXECRES read_res = read_js_or_snapshot_file(output_file_path, snapshot_data_p, &file_bytesize, SNAPSHOT_BUFFER_SIZE); 355 if ((read_res != EXCE_ACE_JERRY_EXEC_OK) || (snapshot_data_p == NULL) || (file_bytesize == 0)) { 356 OhosFree(output_file_path); 357 output_file_path = NULL; 358 return EXCE_ACE_JERRY_READ_FILE_FAILED; 359 } 360 const jerry_snapshot_header_t* header_p = (const jerry_snapshot_header_t*) snapshot_data_p; 361 if (header_p->version != JERRY_SNAPSHOT_VERSION) { 362 OhosFree(output_file_path); 363 output_file_path = NULL; 364 return EXCE_ACE_JERRY_SNAPSHOT_VERSION_ERROR; 365 } 366 OhosFree(output_file_path); 367 output_file_path = NULL; 368 return EXCE_ACE_JERRY_EXEC_OK; 369} /* validate_snapshot */ 370 371/** 372 * when visited file is a js file, transform it into snapshot or check its snapshot's version. 373 */ 374EXECRES visit_js_file(char* input_file_path, EXECRES (*call_back)(char*, char*)) { 375 char* output_file_path = NULL; 376 if ((output_file_path = get_output_file_path(input_file_path)) == NULL) { 377 OhosFree(input_file_path); 378 input_file_path = NULL; 379 return EXCE_ACE_JERRY_SPLICE_OUTPUT_PATH_ERROR; 380 } 381 EXECRES res = call_back(input_file_path, output_file_path); 382 return res; 383} /* visit_js_file */ 384 385/** 386 * visit one single list node. 387 */ 388EXECRES visit_directory(dir_node **end, char* current_path, EXECRES (*call_back)(char*, char*)) { 389 struct dirent* direntp = NULL; 390 struct stat file_stat = { 0 }; 391 char* filename = NULL; 392 char* input_file_path = NULL; 393 DIR* dir = NULL; 394 if ((dir = (DIR*)opendir(current_path)) == NULL) { 395 return EXCE_ACE_JERRY_OPEN_DIR_FAILED; 396 } 397 while ((direntp = (struct dirent*)readdir(dir)) != NULL) { 398 filename = direntp->d_name; 399 if (strncmp(filename, ".", 1) == 0) { 400 continue; 401 } 402 if ((input_file_path = splice_path(current_path, filename)) == NULL) { 403 closedir(dir); 404 return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; 405 } 406 if (stat(input_file_path, &file_stat) < 0) { 407 OhosFree(input_file_path); 408 input_file_path = NULL; 409 closedir(dir); 410 return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; 411 } 412 if (file_stat.st_mode & S_IFDIR) { 413 EXECRES add_directory_res = add_directory_to_pending_list(end, input_file_path); 414 if (add_directory_res != EXCE_ACE_JERRY_EXEC_OK) { 415 closedir(dir); 416 return add_directory_res; 417 } 418 } else if (is_template_file(filename, ".js")) { 419 EXECRES visit_js_res = visit_js_file(input_file_path, call_back); 420 if (visit_js_res != EXCE_ACE_JERRY_EXEC_OK) { 421 closedir(dir); 422 return visit_js_res; 423 } 424 } else { 425 OhosFree(input_file_path); 426 input_file_path = NULL; 427 } 428 } 429 closedir(dir); 430 return EXCE_ACE_JERRY_EXEC_OK; 431} /* visit_directory */ 432 433/** 434 * visit directory from head list node. 435 */ 436EXECRES visit_pending_directories(dir_node **head, dir_node **end, EXECRES (*call_back)(char*, char*)) { 437 dir_node* curr = NULL; 438 char* current_path = NULL; 439 while ((*head)->next != NULL) { 440 curr = (*head)->next; 441 current_path = curr->dir_name; 442 EXECRES visit_res = visit_directory(end, current_path, call_back); 443 if (visit_res != EXCE_ACE_JERRY_EXEC_OK) { 444 free_link(*head); 445 curr = NULL; 446 *end = NULL; 447 return visit_res; 448 } 449 (*head)->next = curr->next; 450 OhosFree(curr->dir_name); 451 curr->dir_name = NULL; 452 OhosFree(curr); 453 curr = NULL; 454 } 455 OhosFree(*head); 456 head = NULL; 457 end = NULL; 458 return EXCE_ACE_JERRY_EXEC_OK; 459} /* visit_pending_directories */ 460 461/** 462 * visit directory and do js to snapshot conversion 463 */ 464EXECRES generate_snapshots(char* filefolder) { 465 char* start_folder = NULL; 466 dir_node* head = NULL; 467 dir_node* end = NULL; 468 469 EXECRES init_res = init_directory_list(filefolder, start_folder, &head, &end); 470 if (init_res != EXCE_ACE_JERRY_EXEC_OK) { 471 return init_res; 472 } 473 EXECRES visit_res = visit_pending_directories(&head, &end, gen_snapshot); 474 if (visit_res != EXCE_ACE_JERRY_EXEC_OK) { 475 return visit_res; 476 } 477 return EXCE_ACE_JERRY_EXEC_OK; 478} /* generate_snapshots */ 479 480/** 481 * visit directory and check snapshot file's version 482 */ 483EXECRES validate_snapshots(char* filefolder) { 484 char* start_folder = NULL; 485 dir_node* head = NULL; 486 dir_node* end = NULL; 487 488 EXECRES init_res = init_directory_list(filefolder, start_folder, &head, &end); 489 if (init_res != EXCE_ACE_JERRY_EXEC_OK) { 490 return init_res; 491 } 492 EXECRES visit_res = visit_pending_directories(&head, &end, validate_snapshot); 493 if (visit_res != EXCE_ACE_JERRY_EXEC_OK) { 494 return visit_res; 495 } 496 return EXCE_ACE_JERRY_EXEC_OK; 497} /* validate_snapshots */ 498 499/** 500 * visit directory and do js to bytecode conversion ON IAR 501 */ 502EXECRES walk_directory(char* filefolder) { 503 EXECRES generate_res = generate_snapshots(filefolder); 504 if (generate_res != EXCE_ACE_JERRY_EXEC_OK) { 505 return generate_res; 506 } 507#if defined (JERRY_ENABLE_SNAPSHOT_VERSION_CHECK) && (JERRY_ENABLE_SNAPSHOT_VERSION_CHECK == 1) 508 return validate_snapshots(filefolder); 509#else 510 return EXCE_ACE_JERRY_EXEC_OK; 511#endif 512} /* walk_directory */ 513 514/** 515 * when convertion failed, traverse directory and delete all created bytecode files 516 */ 517EXECRES walk_del_bytecode(char* filefolder) { 518 DIR* dir; 519 struct dirent* direntp; 520 struct stat file_stat = { 0 }; 521 char* filename = NULL; 522 char* current_path = NULL; 523 char* input_file_path = NULL; 524 char* start_folder = NULL; 525 dir_node *head, *curr, *end, *new_node; 526 int filefolder_len = strlen(filefolder) + 1; 527 528 if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { 529 return EXCE_ACE_JERRY_INPUT_PATH_ERROR; 530 } 531 if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { 532 return EXCE_ACE_JERRY_MALLOC_ERROR; 533 } 534 if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { 535 OhosFree(start_folder); 536 start_folder = NULL; 537 return EXCE_ACE_JERRY_INPUT_PATH_ERROR; 538 } 539 if ((head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { 540 OhosFree(start_folder); 541 start_folder = NULL; 542 return EXCE_ACE_JERRY_LINKLIST_ERROR; 543 } 544 if ((end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { 545 OhosFree(start_folder); 546 start_folder = NULL; 547 OhosFree(head); 548 head = NULL; 549 return EXCE_ACE_JERRY_LINKLIST_ERROR; 550 } 551 head->dir_name = NULL; 552 head->next = end; 553 end->dir_name = start_folder; 554 end->next = NULL; 555 556 while (head->next != NULL) { 557 curr = head->next; 558 current_path = curr->dir_name; 559 if ((dir = (DIR*)opendir(current_path)) == NULL) { 560 free_link(head); 561 curr = NULL; 562 end = NULL; 563 return EXCE_ACE_JERRY_OPEN_DIR_FAILED; 564 } 565 while ((direntp = (struct dirent*)readdir(dir)) != NULL) { 566 filename = direntp->d_name; 567 if (strncmp(filename, ".", 1) == 0) { 568 continue; 569 } 570 if ((input_file_path = splice_path(current_path, filename)) == NULL) { 571 closedir(dir); 572 free_link(head); 573 curr = NULL; 574 end = NULL; 575 return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; 576 } 577 if (stat(input_file_path, &file_stat) < 0) { 578 closedir(dir); 579 OhosFree(input_file_path); 580 input_file_path = NULL; 581 free_link(head); 582 curr = NULL; 583 end = NULL; 584 return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; 585 } 586 if (file_stat.st_mode & S_IFDIR) { 587 // file now is file folder 588 if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { 589 closedir(dir); 590 OhosFree(input_file_path); 591 input_file_path = NULL; 592 free_link(head); 593 curr = NULL; 594 end = NULL; 595 return EXCE_ACE_JERRY_LINKLIST_ERROR; 596 } 597 // input_file_path for dir will be freed when that node is freed 598 new_node->dir_name = input_file_path; 599 new_node->next = NULL; 600 end->next = new_node; 601 end = new_node; 602 new_node = NULL; 603 } else if ((is_template_file(filename, ".bc")) && (unlink(input_file_path) != F_OK)) { 604 //file now is .bc file and unlink file failed 605 closedir(dir); 606 OhosFree(input_file_path); 607 input_file_path = NULL; 608 free_link(head); 609 curr = NULL; 610 end = NULL; 611 return EXCE_ACE_JERRY_UNLINKFILE_ERROR; 612 } else { 613 OhosFree(input_file_path); 614 input_file_path = NULL; 615 } 616 } 617 closedir(dir); 618 head->next = curr->next; 619 OhosFree(curr->dir_name); 620 curr->dir_name = NULL; 621 OhosFree(curr); 622 curr = NULL; 623 } 624 OhosFree(head); 625 head = NULL; 626 end = NULL; 627 return EXCE_ACE_JERRY_EXEC_OK; 628} /* walk_del_bytecode */ 629 630#endif // end JERRY_FOR_IAR_CONFIG 631