/* * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. * Description: Definition of source file for generating bytecode. * Create: 2020/09/07 */ #ifdef JERRY_FOR_IAR_CONFIG #include "generate-bytecode.h" #include #include "config-gt.h" #include "config-jupiter.h" #define VERSION_LEN 30 #define ONETIME_MAX_OPTBYTES 4096 // max size for reading and writing at onetime // jerry version code char version_str[VERSION_LEN]; // secure functions extern int memset_s(void *dest, size_t destMax, int c, size_t count); extern int strcpy_s(char *strDest, size_t destMax, const char *strSrc); extern int strcat_s(char *strDest, size_t destMax, const char *strSrc); extern int strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); extern int sprintf_s(char *strDest, size_t destMax, const char *format, ...); extern int strncpy_s(char *strDest, size_t destMax, const char *strSrc, size_t count); #ifdef JERRY_IAR_JUPITER extern uint8_t* input_buffer; extern uint8_t* snapshot_buffer; #endif // JERRY_IAR_JUPITER /** * jerry snapshot format version */ char* get_jerry_version_no() { if (sprintf_s(version_str, sizeof(version_str), "JERRY_SNAPSHOT_VERSION_%u", JERRY_SNAPSHOT_VERSION) < 0) { return NULL; } return version_str; } /* get_jerry_version_no */ /** * splice path and filename */ char* splice_path(char* str1, char* str2) { int len1 = strlen(str1); int len2 = strlen(str2); int res_len = len1 + len2 + 1; // str1 + "/" + str2 char* res = (char*)OhosMalloc(MEM_TYPE_JERRY, (res_len + 1) * sizeof(char)); if (res == NULL) { return NULL; } if (memset_s(res, res_len + 1, 0, res_len + 1) != 0) { OhosFree(res); res = NULL; return NULL; } if (strcpy_s(res, len1 + 1, str1) != 0) { OhosFree(res); res = NULL; return NULL; } if ((strcat_s(res, len1 + strlen("/") + 1, "/") != 0) || (strcat_s(res, res_len + 1, str2) != 0)) { OhosFree(res); res = NULL; return NULL; } return res; } /* splice_path */ /** * judge if is template(js/bc) file */ bool is_template_file(char* filename, char* template) { const char* pFile; pFile = strrchr(filename, '.'); if ((pFile != NULL) && (strcmp(pFile, template) == 0)) { return true; } return false; } /* is_template_file */ /** * get output snapshot file absolutely path */ char* get_output_file_path(char* input_file_path) { int len = strlen(input_file_path); char* output_file_path = (char*)OhosMalloc(MEM_TYPE_JERRY, (len + 1) * sizeof(char)); if (output_file_path == NULL) { return NULL; } if (memset_s(output_file_path, len + 1, 0, len + 1) != 0) { OhosFree(output_file_path); output_file_path = NULL; return NULL; } if (strncpy_s(output_file_path, len, input_file_path, len - strlen(".js")) != 0) { OhosFree(output_file_path); output_file_path = NULL; return NULL; } output_file_path[len-3] = '.'; output_file_path[len-2] = 'b'; output_file_path[len-1] = 'c'; output_file_path[len] = '\0'; return output_file_path; } /* get_output_file_path */ /** * read js bundle file or snapshot file by Fragement */ EXECRES read_js_or_snapshot_file(char* filename, uint8_t* target_file, int* file_bytesize, int buffer_capacity) { int fd = 0; struct stat file_stat = { 0 }; int remain_to_read = 0; int here_to_read = 0; int tmp_read = 0; int read_offset = 0; fd = open(filename, O_RDONLY, S_IREAD); if (fd < 0) { // Error: failed to open file return EXCE_ACE_JERRY_OPEN_FILE_FAILED; } if (fstat(fd, &file_stat) < 0) { close(fd); return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; } *file_bytesize = file_stat.st_size; if (*file_bytesize > buffer_capacity) { close(fd); return EXCE_ACE_JERRY_FILE_TOO_LARGE; } remain_to_read = *file_bytesize; while (remain_to_read > 0) { here_to_read = (remain_to_read > ONETIME_MAX_OPTBYTES) ? ONETIME_MAX_OPTBYTES : remain_to_read; tmp_read = read(fd, target_file + read_offset, here_to_read); if (tmp_read < 0 || tmp_read != here_to_read) { close(fd); // Error: failed to read file return EXCE_ACE_JERRY_READ_FILE_FAILED; } read_offset = read_offset + here_to_read; remain_to_read = remain_to_read - here_to_read; } if (read_offset != *file_bytesize) { close(fd); // Error: failed to successfully read file return EXCE_ACE_JERRY_READ_FILE_FAILED; } close(fd); return EXCE_ACE_JERRY_EXEC_OK; } /* read_js_or_snapshot_file */ /** * write snapshot file by Fragment */ EXECRES write_snapshot(char* output_file_name_path, size_t snapshot_size) { int fd = 0; int res = 0; int remain_to_write = 0; int here_to_write = 0; int write_offset = 0; fd = open(output_file_name_path, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); if (fd < 0) { // Error: Unable to open snapshot file return EXCE_ACE_JERRY_OPEN_FILE_FAILED; } remain_to_write = snapshot_size; while (remain_to_write > 0) { here_to_write = (remain_to_write > ONETIME_MAX_OPTBYTES) ? ONETIME_MAX_OPTBYTES : remain_to_write; res = write(fd, snapshot_buffer + write_offset, here_to_write); if (res <= 0 || res != here_to_write) { close(fd); // Error: Unable to write snapshot file return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; } write_offset = write_offset + here_to_write; remain_to_write = remain_to_write - here_to_write; } if (write_offset != snapshot_size) { close(fd); // Error: Unable to successfully write snapshot file return EXCE_ACE_JERRY_WRITE_SNAPSHOT_FILE_FAILED; } close(fd); return EXCE_ACE_JERRY_EXEC_OK; } /* write_snapshot */ /** * struct for Directory Node */ typedef struct Node { char* dir_name; struct Node* next; } dir_node; /** * free the memory for linkedlist */ void free_link(dir_node* head) { dir_node* tmp = NULL; while (head != NULL) { tmp = head; head = head->next; if (tmp->dir_name != NULL) { OhosFree(tmp->dir_name); tmp->dir_name = NULL; } OhosFree(tmp); tmp = NULL; } } /* free_link */ /** * generate snapshot file */ EXECRES generate_snapshot_file(char* input_file, char* output_file) { uint8_t* target_Js = input_buffer; jerry_value_t generate_result; size_t snapshot_size = 0; EXECRES write_res = EXCE_ACE_JERRY_EXEC_OK; bool convert_state = false; int file_bytesize = 0; EXECRES read_res = EXCE_ACE_JERRY_EXEC_OK; if (input_file == NULL || output_file == NULL) { return EXCE_ACE_JERRY_NULL_PATH; } read_res = read_js_or_snapshot_file(input_file, target_Js, &file_bytesize, INPUTJS_BUFFER_SIZE); if (read_res != EXCE_ACE_JERRY_EXEC_OK) { return read_res; } generate_result = jerry_generate_snapshot ( NULL, 0, target_Js, file_bytesize, 0, (uint32_t* )snapshot_buffer, SNAPSHOT_BUFFER_SIZE); convert_state = jerry_value_is_error(generate_result) || !jerry_value_is_number(generate_result); if (convert_state) { // Error: Generating snapshot failed jerry_release_value(generate_result); return EXCE_ACE_JERRY_GENERATE_SNAPSHOT_FAILED; } snapshot_size = (size_t)jerry_get_number_value(generate_result); jerry_release_value(generate_result); write_res = write_snapshot(output_file, snapshot_size); if (write_res != EXCE_ACE_JERRY_EXEC_OK) { // Error: Writing snapshot file failed return write_res; } return EXCE_ACE_JERRY_EXEC_OK; }/* generate_snapshot_file */ /** * init the linked list for files in filefolder. */ EXECRES init_directory_list(char* filefolder, char* start_folder, dir_node **head, dir_node **end) { struct stat file_stat = { 0 }; int filefolder_len = strlen(filefolder) + 1; if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { return EXCE_ACE_JERRY_INPUT_PATH_ERROR; } if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { return EXCE_ACE_JERRY_MALLOC_ERROR; } if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { OhosFree(start_folder); start_folder = NULL; return EXCE_ACE_JERRY_INPUT_PATH_ERROR; } if ((*head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { OhosFree(start_folder); start_folder = NULL; return EXCE_ACE_JERRY_LINKLIST_ERROR; } if ((*end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { OhosFree(start_folder); start_folder = NULL; OhosFree(*head); *head = NULL; return EXCE_ACE_JERRY_LINKLIST_ERROR; } (*head)->dir_name = NULL; (*head)->next = *end; (*end)->dir_name = start_folder; (*end)->next = NULL; return EXCE_ACE_JERRY_EXEC_OK; } /* init_directory_list */ /** * when visited node is a directory, add it to the node list's end. */ EXECRES add_directory_to_pending_list(dir_node **end, char* input_file_path) { dir_node *new_node = NULL; if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { OhosFree(input_file_path); input_file_path = NULL; return EXCE_ACE_JERRY_LINKLIST_ERROR; } // input_file_path for dir will be freed when that node is freed new_node->dir_name = input_file_path; new_node->next = NULL; (*end)->next = new_node; *end = new_node; new_node = NULL; return EXCE_ACE_JERRY_EXEC_OK; } /* add_directory_to_pending_list */ /** * transform this js file into snapshot. */ EXECRES gen_snapshot(char* input_file_path, char* output_file_path) { jerry_init_flag_t flags = JERRY_INIT_EMPTY; jerry_init (flags); EXECRES generate_val = EXCE_ACE_JERRY_EXEC_OK; generate_val = generate_snapshot_file(input_file_path, output_file_path); jerry_cleanup(); OhosFree(output_file_path); output_file_path = NULL; OhosFree(input_file_path); input_file_path = NULL; if (generate_val != EXCE_ACE_JERRY_EXEC_OK) { return generate_val; // return error_code } return EXCE_ACE_JERRY_EXEC_OK; } /* gen_snapshot */ /** * validate snapshot's version. */ EXECRES validate_snapshot(char* input_file_path, char* output_file_path) { uint8_t* snapshot_data_p = snapshot_buffer; int file_bytesize = 0; OhosFree(input_file_path); input_file_path = NULL; EXECRES read_res = read_js_or_snapshot_file(output_file_path, snapshot_data_p, &file_bytesize, SNAPSHOT_BUFFER_SIZE); if ((read_res != EXCE_ACE_JERRY_EXEC_OK) || (snapshot_data_p == NULL) || (file_bytesize == 0)) { OhosFree(output_file_path); output_file_path = NULL; return EXCE_ACE_JERRY_READ_FILE_FAILED; } const jerry_snapshot_header_t* header_p = (const jerry_snapshot_header_t*) snapshot_data_p; if (header_p->version != JERRY_SNAPSHOT_VERSION) { OhosFree(output_file_path); output_file_path = NULL; return EXCE_ACE_JERRY_SNAPSHOT_VERSION_ERROR; } OhosFree(output_file_path); output_file_path = NULL; return EXCE_ACE_JERRY_EXEC_OK; } /* validate_snapshot */ /** * when visited file is a js file, transform it into snapshot or check its snapshot's version. */ EXECRES visit_js_file(char* input_file_path, EXECRES (*call_back)(char*, char*)) { char* output_file_path = NULL; if ((output_file_path = get_output_file_path(input_file_path)) == NULL) { OhosFree(input_file_path); input_file_path = NULL; return EXCE_ACE_JERRY_SPLICE_OUTPUT_PATH_ERROR; } EXECRES res = call_back(input_file_path, output_file_path); return res; } /* visit_js_file */ /** * visit one single list node. */ EXECRES visit_directory(dir_node **end, char* current_path, EXECRES (*call_back)(char*, char*)) { struct dirent* direntp = NULL; struct stat file_stat = { 0 }; char* filename = NULL; char* input_file_path = NULL; DIR* dir = NULL; if ((dir = (DIR*)opendir(current_path)) == NULL) { return EXCE_ACE_JERRY_OPEN_DIR_FAILED; } while ((direntp = (struct dirent*)readdir(dir)) != NULL) { filename = direntp->d_name; if (strncmp(filename, ".", 1) == 0) { continue; } if ((input_file_path = splice_path(current_path, filename)) == NULL) { closedir(dir); return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; } if (stat(input_file_path, &file_stat) < 0) { OhosFree(input_file_path); input_file_path = NULL; closedir(dir); return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; } if (file_stat.st_mode & S_IFDIR) { EXECRES add_directory_res = add_directory_to_pending_list(end, input_file_path); if (add_directory_res != EXCE_ACE_JERRY_EXEC_OK) { closedir(dir); return add_directory_res; } } else if (is_template_file(filename, ".js")) { EXECRES visit_js_res = visit_js_file(input_file_path, call_back); if (visit_js_res != EXCE_ACE_JERRY_EXEC_OK) { closedir(dir); return visit_js_res; } } else { OhosFree(input_file_path); input_file_path = NULL; } } closedir(dir); return EXCE_ACE_JERRY_EXEC_OK; } /* visit_directory */ /** * visit directory from head list node. */ EXECRES visit_pending_directories(dir_node **head, dir_node **end, EXECRES (*call_back)(char*, char*)) { dir_node* curr = NULL; char* current_path = NULL; while ((*head)->next != NULL) { curr = (*head)->next; current_path = curr->dir_name; EXECRES visit_res = visit_directory(end, current_path, call_back); if (visit_res != EXCE_ACE_JERRY_EXEC_OK) { free_link(*head); curr = NULL; *end = NULL; return visit_res; } (*head)->next = curr->next; OhosFree(curr->dir_name); curr->dir_name = NULL; OhosFree(curr); curr = NULL; } OhosFree(*head); head = NULL; end = NULL; return EXCE_ACE_JERRY_EXEC_OK; } /* visit_pending_directories */ /** * visit directory and do js to snapshot conversion */ EXECRES generate_snapshots(char* filefolder) { char* start_folder = NULL; dir_node* head = NULL; dir_node* end = NULL; EXECRES init_res = init_directory_list(filefolder, start_folder, &head, &end); if (init_res != EXCE_ACE_JERRY_EXEC_OK) { return init_res; } EXECRES visit_res = visit_pending_directories(&head, &end, gen_snapshot); if (visit_res != EXCE_ACE_JERRY_EXEC_OK) { return visit_res; } return EXCE_ACE_JERRY_EXEC_OK; } /* generate_snapshots */ /** * visit directory and check snapshot file's version */ EXECRES validate_snapshots(char* filefolder) { char* start_folder = NULL; dir_node* head = NULL; dir_node* end = NULL; EXECRES init_res = init_directory_list(filefolder, start_folder, &head, &end); if (init_res != EXCE_ACE_JERRY_EXEC_OK) { return init_res; } EXECRES visit_res = visit_pending_directories(&head, &end, validate_snapshot); if (visit_res != EXCE_ACE_JERRY_EXEC_OK) { return visit_res; } return EXCE_ACE_JERRY_EXEC_OK; } /* validate_snapshots */ /** * visit directory and do js to bytecode conversion ON IAR */ EXECRES walk_directory(char* filefolder) { EXECRES generate_res = generate_snapshots(filefolder); if (generate_res != EXCE_ACE_JERRY_EXEC_OK) { return generate_res; } #if defined (JERRY_ENABLE_SNAPSHOT_VERSION_CHECK) && (JERRY_ENABLE_SNAPSHOT_VERSION_CHECK == 1) return validate_snapshots(filefolder); #else return EXCE_ACE_JERRY_EXEC_OK; #endif } /* walk_directory */ /** * when convertion failed, traverse directory and delete all created bytecode files */ EXECRES walk_del_bytecode(char* filefolder) { DIR* dir; struct dirent* direntp; struct stat file_stat = { 0 }; char* filename = NULL; char* current_path = NULL; char* input_file_path = NULL; char* start_folder = NULL; dir_node *head, *curr, *end, *new_node; int filefolder_len = strlen(filefolder) + 1; if ((filefolder == NULL) || (stat(filefolder, &file_stat) < 0)) { return EXCE_ACE_JERRY_INPUT_PATH_ERROR; } if ((start_folder = (char*)OhosMalloc(MEM_TYPE_JERRY, filefolder_len)) == NULL) { return EXCE_ACE_JERRY_MALLOC_ERROR; } if (strcpy_s(start_folder, filefolder_len, filefolder) != 0) { OhosFree(start_folder); start_folder = NULL; return EXCE_ACE_JERRY_INPUT_PATH_ERROR; } if ((head = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { OhosFree(start_folder); start_folder = NULL; return EXCE_ACE_JERRY_LINKLIST_ERROR; } if ((end = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { OhosFree(start_folder); start_folder = NULL; OhosFree(head); head = NULL; return EXCE_ACE_JERRY_LINKLIST_ERROR; } head->dir_name = NULL; head->next = end; end->dir_name = start_folder; end->next = NULL; while (head->next != NULL) { curr = head->next; current_path = curr->dir_name; if ((dir = (DIR*)opendir(current_path)) == NULL) { free_link(head); curr = NULL; end = NULL; return EXCE_ACE_JERRY_OPEN_DIR_FAILED; } while ((direntp = (struct dirent*)readdir(dir)) != NULL) { filename = direntp->d_name; if (strncmp(filename, ".", 1) == 0) { continue; } if ((input_file_path = splice_path(current_path, filename)) == NULL) { closedir(dir); free_link(head); curr = NULL; end = NULL; return EXCE_ACE_JERRY_SPLICE_PATH_ERROR; } if (stat(input_file_path, &file_stat) < 0) { closedir(dir); OhosFree(input_file_path); input_file_path = NULL; free_link(head); curr = NULL; end = NULL; return EXCE_ACE_JERRY_GET_FILE_STAT_ERROR; } if (file_stat.st_mode & S_IFDIR) { // file now is file folder if ((new_node = (dir_node*)OhosMalloc(MEM_TYPE_JERRY, sizeof(dir_node))) == NULL) { closedir(dir); OhosFree(input_file_path); input_file_path = NULL; free_link(head); curr = NULL; end = NULL; return EXCE_ACE_JERRY_LINKLIST_ERROR; } // input_file_path for dir will be freed when that node is freed new_node->dir_name = input_file_path; new_node->next = NULL; end->next = new_node; end = new_node; new_node = NULL; } else if ((is_template_file(filename, ".bc")) && (unlink(input_file_path) != F_OK)) { //file now is .bc file and unlink file failed closedir(dir); OhosFree(input_file_path); input_file_path = NULL; free_link(head); curr = NULL; end = NULL; return EXCE_ACE_JERRY_UNLINKFILE_ERROR; } else { OhosFree(input_file_path); input_file_path = NULL; } } closedir(dir); head->next = curr->next; OhosFree(curr->dir_name); curr->dir_name = NULL; OhosFree(curr); curr = NULL; } OhosFree(head); head = NULL; end = NULL; return EXCE_ACE_JERRY_EXEC_OK; } /* walk_del_bytecode */ #endif // end JERRY_FOR_IAR_CONFIG