unleashed-firmware/lib/mjs/mjs_bcode.c
Nikolay Minaylov 0154018363
[FL-3579, FL-3601, FL-3714] JavaScript runner (#3286)
* FBT: cdefines to env, libs order
* API: strtod, modf, itoa, calloc
* Apps: elk js
* Apps: mjs
* JS: scripts as assets
* mjs: composite resolver
* mjs: stack trace
* ELK JS example removed
* MJS thread, MJS lib modified to support script interruption
* JS console UI
* Module system, BadUSB bindings rework
* JS notifications, simple dialog, BadUSB demo
* Custom dialogs, dialog demo
* MJS as system library, some dirty hacks to make it compile
* Plugin-based js modules
* js_uart(BadUART) module
* js_uart: support for byte array arguments
* Script icon and various fixes
* File browser: multiple extensions filter, running js scripts from app loader
* Running js scripts from archive browser
* JS Runner as system app
* Example scripts moved to /ext/apps/Scripts
* JS bytecode listing generation
* MJS builtin printf cleanup
* JS examples cleanup
* mbedtls version fix
* Unused lib cleanup
* Making PVS happy & TODOs cleanup
* TODOs cleanup #2
* MJS: initial typed arrays support
* JS: fix mem leak in uart destructor

Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2024-02-12 15:54:32 +07:00

147 lines
4.5 KiB
C

/*
* Copyright (c) 2017 Cesanta Software Limited
* All rights reserved
*/
#include "common/cs_varint.h"
#include "mjs_internal.h"
#include "mjs_bcode.h"
#include "mjs_core.h"
#include "mjs_tok.h"
static void add_lineno_map_item(struct pstate* pstate) {
if(pstate->last_emitted_line_no < pstate->line_no) {
int offset = pstate->cur_idx - pstate->start_bcode_idx;
size_t offset_llen = cs_varint_llen(offset);
size_t lineno_llen = cs_varint_llen(pstate->line_no);
mbuf_resize(
&pstate->offset_lineno_map,
pstate->offset_lineno_map.size + offset_llen + lineno_llen);
/* put offset */
cs_varint_encode(
offset,
(uint8_t*)pstate->offset_lineno_map.buf + pstate->offset_lineno_map.len,
offset_llen);
pstate->offset_lineno_map.len += offset_llen;
/* put line_no */
cs_varint_encode(
pstate->line_no,
(uint8_t*)pstate->offset_lineno_map.buf + pstate->offset_lineno_map.len,
lineno_llen);
pstate->offset_lineno_map.len += lineno_llen;
pstate->last_emitted_line_no = pstate->line_no;
}
}
MJS_PRIVATE void emit_byte(struct pstate* pstate, uint8_t byte) {
add_lineno_map_item(pstate);
mbuf_insert(&pstate->mjs->bcode_gen, pstate->cur_idx, &byte, sizeof(byte));
pstate->cur_idx += sizeof(byte);
}
MJS_PRIVATE void emit_int(struct pstate* pstate, int64_t n) {
struct mbuf* b = &pstate->mjs->bcode_gen;
size_t llen = cs_varint_llen(n);
add_lineno_map_item(pstate);
mbuf_insert(b, pstate->cur_idx, NULL, llen);
cs_varint_encode(n, (uint8_t*)b->buf + pstate->cur_idx, llen);
pstate->cur_idx += llen;
}
MJS_PRIVATE void emit_str(struct pstate* pstate, const char* ptr, size_t len) {
struct mbuf* b = &pstate->mjs->bcode_gen;
size_t llen = cs_varint_llen(len);
add_lineno_map_item(pstate);
mbuf_insert(b, pstate->cur_idx, NULL, llen + len);
cs_varint_encode(len, (uint8_t*)b->buf + pstate->cur_idx, llen);
memcpy(b->buf + pstate->cur_idx + llen, ptr, len);
pstate->cur_idx += llen + len;
}
MJS_PRIVATE int
mjs_bcode_insert_offset(struct pstate* p, struct mjs* mjs, size_t offset, size_t v) {
int llen = (int)cs_varint_llen(v);
int diff = llen - MJS_INIT_OFFSET_SIZE;
assert(offset < mjs->bcode_gen.len);
if(diff > 0) {
mbuf_resize(&mjs->bcode_gen, mjs->bcode_gen.size + diff);
}
/*
* Offset is going to take more than one was reserved, so, move the data
* forward
*/
memmove(
mjs->bcode_gen.buf + offset + llen,
mjs->bcode_gen.buf + offset + MJS_INIT_OFFSET_SIZE,
mjs->bcode_gen.len - offset - MJS_INIT_OFFSET_SIZE);
mjs->bcode_gen.len += diff;
cs_varint_encode(v, (uint8_t*)mjs->bcode_gen.buf + offset, llen);
/*
* If current parsing index is after the offset at which we've inserted new
* varint, the index might need to be adjusted
*/
if(p->cur_idx >= (int)offset) {
p->cur_idx += diff;
}
return diff;
}
MJS_PRIVATE void mjs_bcode_part_add(struct mjs* mjs, const struct mjs_bcode_part* bp) {
mbuf_append(&mjs->bcode_parts, bp, sizeof(*bp));
}
MJS_PRIVATE struct mjs_bcode_part* mjs_bcode_part_get(struct mjs* mjs, int num) {
assert(num < mjs_bcode_parts_cnt(mjs));
return (struct mjs_bcode_part*)(mjs->bcode_parts.buf + num * sizeof(struct mjs_bcode_part));
}
MJS_PRIVATE struct mjs_bcode_part* mjs_bcode_part_get_by_offset(struct mjs* mjs, size_t offset) {
int i;
int parts_cnt = mjs_bcode_parts_cnt(mjs);
struct mjs_bcode_part* bp = NULL;
if(offset >= mjs->bcode_len) {
return NULL;
}
for(i = 0; i < parts_cnt; i++) {
bp = mjs_bcode_part_get(mjs, i);
if(offset < bp->start_idx + bp->data.len) {
break;
}
}
/* given the non-corrupted data, the needed part must be found */
assert(i < parts_cnt);
return bp;
}
MJS_PRIVATE int mjs_bcode_parts_cnt(struct mjs* mjs) {
return mjs->bcode_parts.len / sizeof(struct mjs_bcode_part);
}
MJS_PRIVATE void mjs_bcode_commit(struct mjs* mjs) {
struct mjs_bcode_part bp;
memset(&bp, 0, sizeof(bp));
/* Make sure the bcode doesn't occupy any extra space */
mbuf_trim(&mjs->bcode_gen);
/* Transfer the ownership of the bcode data */
bp.data.p = mjs->bcode_gen.buf;
bp.data.len = mjs->bcode_gen.len;
mbuf_init(&mjs->bcode_gen, 0);
bp.start_idx = mjs->bcode_len;
bp.exec_res = MJS_ERRS_CNT;
mjs_bcode_part_add(mjs, &bp);
mjs->bcode_len += bp.data.len;
}