Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FL-3579, FL-3601, FL-3714] JavaScript runner #3286

Merged
merged 38 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
22c638b
FBT: cdefines to env, libs order
DrZlo13 Sep 15, 2023
5ce03c5
API: strtod, modf, itoa, calloc
DrZlo13 Sep 15, 2023
a57c730
Apps: elk js
DrZlo13 Sep 15, 2023
58781b5
Apps: mjs
DrZlo13 Sep 15, 2023
15be27b
JS: scripts as assets
DrZlo13 Sep 15, 2023
5b76559
mjs: composite resolver
DrZlo13 Sep 15, 2023
6130d31
mjs: stack trace
DrZlo13 Sep 15, 2023
e2c817e
ELK JS example removed
nminaylov Sep 19, 2023
f032aa2
MJS thread, MJS lib modified to support script interruption
nminaylov Sep 25, 2023
c49334f
JS console UI
nminaylov Oct 4, 2023
f972937
Module system, BadUSB bindings rework
nminaylov Oct 6, 2023
5e58b0a
JS notifications, simple dialog, BadUSB demo
nminaylov Oct 10, 2023
7cec4e8
Custom dialogs, dialog demo
nminaylov Oct 13, 2023
a6791dc
MJS as system library, some dirty hacks to make it compile
nminaylov Oct 17, 2023
573d912
Plugin-based js modules
nminaylov Oct 18, 2023
2d3e23d
Merge branch 'dev' into private/nm/js_app
nminaylov Oct 18, 2023
a8f3dca
js_uart(BadUART) module
nminaylov Oct 27, 2023
49920a7
js_uart: support for byte array arguments
nminaylov Oct 30, 2023
7032c90
Script icon and various fixes
nminaylov Nov 3, 2023
ad0b1b9
Merge branch 'dev' into private/nm/js_app
nminaylov Nov 13, 2023
9823d52
File browser: multiple extensions filter, running js scripts from app…
nminaylov Nov 22, 2023
7c1ad35
Running js scripts from archive browser
nminaylov Nov 22, 2023
22d9d1a
JS Runner as system app
nminaylov Nov 24, 2023
584f0d8
Merge branch 'dev' into private/nm/js_app
nminaylov Nov 24, 2023
96e33c2
Example scripts moved to /ext/apps/Scripts
nminaylov Nov 24, 2023
6be0df3
JS bytecode listing generation
nminaylov Nov 27, 2023
3e30df2
MJS builtin printf cleanup
nminaylov Dec 12, 2023
973467e
JS examples cleanup
nminaylov Dec 12, 2023
bb827fb
Merge branch 'dev' into nm/js_runner
nminaylov Dec 12, 2023
05611bd
mbedtls version fix
nminaylov Dec 12, 2023
102e891
Unused lib cleanup
nminaylov Dec 12, 2023
98ec2ad
Making PVS happy & TODOs cleanup
nminaylov Dec 12, 2023
4531909
TODOs cleanup #2
nminaylov Dec 12, 2023
471df94
Merge remote-tracking branch 'origin/dev' into nm/js_runner
skotopes Dec 19, 2023
d916ff4
Merge branch 'dev' into nm/js_runner
skotopes Dec 19, 2023
647decc
MJS: initial typed arrays support
nminaylov Dec 28, 2023
211e914
Merge remote-tracking branch 'origin/dev' into nm/js_runner
skotopes Feb 12, 2024
0e8a785
JS: fix mem leak in uart destructor
skotopes Feb 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
JS bytecode listing generation
  • Loading branch information
nminaylov committed Nov 27, 2023
commit 6be0df3981c3cffa3118ed3024435f0849ab2d31
2 changes: 1 addition & 1 deletion applications/system/js_app/examples/apps/Scripts/req.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
let math = load("/ext/apps_assets/m_js/api.js");
let math = load("/ext/apps/Scripts/api.js");
let result = math.add(5, 10);
print(result);
2 changes: 1 addition & 1 deletion applications/system/js_app/js_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <toolbox/path.h>
#include <assets_icons.h>

#define TAG "MJS app"
#define TAG "JS app"

typedef struct {
JsThread* js_thread;
Expand Down
36 changes: 36 additions & 0 deletions applications/system/js_app/js_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <loader/firmware_api/firmware_api.h>
#include <flipper_application/api_hashtable/api_hashtable.h>
#include <flipper_application/plugins/composite_resolver.h>
#include <furi_hal.h>
#include "plugin_api/app_api_interface.h"
#include "js_thread.h"
#include "js_thread_i.h"
Expand Down Expand Up @@ -209,6 +210,22 @@ static void mjs_global_to_hex_string(struct mjs* mjs) {
mjs_return(mjs, ret);
}

static void js_dump_write_callback(void* ctx, const char* format, ...) {
File* file = ctx;
furi_assert(ctx);

FuriString* str = furi_string_alloc();

va_list args;
va_start(args, format);
furi_string_vprintf(str, format, args);
furi_string_cat(str, "\n");
va_end(args);

storage_file_write(file, furi_string_get_cstr(str), furi_string_size(str));
furi_string_free(str);
}

static int32_t js_thread(void* arg) {
JsThread* worker = arg;
worker->resolver = composite_api_resolver_alloc();
Expand Down Expand Up @@ -238,6 +255,25 @@ static int32_t js_thread(void* arg) {

mjs_err_t err = mjs_exec_file(mjs, furi_string_get_cstr(worker->path), NULL);

if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
FuriString* dump_path = furi_string_alloc_set(worker->path);
furi_string_cat(dump_path, ".lst");

Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);

if(storage_file_open(
file, furi_string_get_cstr(dump_path), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
mjs_disasm_all(mjs, js_dump_write_callback, file);
}

storage_file_close(file);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);

furi_string_free(dump_path);
}

if(err != MJS_OK) {
FURI_LOG_E(TAG, "Exec error: %s", mjs_strerror(mjs, err));
if(worker->app_callback) {
Expand Down
104 changes: 60 additions & 44 deletions lib/mjs/mjs_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "mjs_string.h"
#include "mjs_util.h"
#include "mjs_tok.h"
#include <furi.h>

const char* mjs_typeof(mjs_val_t v) {
return mjs_stringify_type(mjs_get_type(v));
Expand Down Expand Up @@ -93,8 +94,6 @@ void mjs_fprintf(mjs_val_t v, struct mjs* mjs, FILE* fp) {
mjs_jprintf(v, mjs, &out);
}

#if MJS_ENABLE_DEBUG

MJS_PRIVATE const char* opcodetostr(uint8_t opcode) {
static const char* names[] = {
"NOP",
Expand Down Expand Up @@ -143,24 +142,27 @@ MJS_PRIVATE const char* opcodetostr(uint8_t opcode) {
return name;
}

MJS_PRIVATE size_t mjs_disasm_single(const uint8_t* code, size_t i) {
MJS_PRIVATE size_t
mjs_disasm_single(const uint8_t* code, size_t i, MjsPrintCallback print_cb, void* print_ctx) {
char buf[40];
size_t start_i = i;
size_t llen;
uint64_t n;

snprintf(buf, sizeof(buf), "\t%-3u %-8s", (unsigned)i, opcodetostr(code[i]));
furi_assert(print_cb);

snprintf(buf, sizeof(buf), "%-3u\t%-8s", (unsigned)i, opcodetostr(code[i]));

switch(code[i]) {
case OP_PUSH_FUNC: {
cs_varint_decode(&code[i + 1], ~0, &n, &llen);
LOG(LL_VERBOSE_DEBUG, ("%s %04u", buf, (unsigned)(i - n)));
print_cb(print_ctx, "%s %04u", buf, (unsigned)(i - n));
i += llen;
break;
}
case OP_PUSH_INT: {
cs_varint_decode(&code[i + 1], ~0, &n, &llen);
LOG(LL_VERBOSE_DEBUG, ("%s\t%lu", buf, (unsigned long)n));
print_cb(print_ctx, "%s\t%lu", buf, (unsigned long)n);
i += llen;
break;
}
Expand All @@ -169,15 +171,15 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t* code, size_t i) {
uint64_t arg_no;
cs_varint_decode(&code[i + 1], ~0, &arg_no, &llen);
cs_varint_decode(&code[i + llen + 1], ~0, &n, &llen2);
LOG(LL_VERBOSE_DEBUG,
("%s\t[%.*s] %u", buf, (int)n, code + i + 1 + llen + llen2, (unsigned)arg_no));
print_cb(
print_ctx, "%s\t[%.*s] %u", buf, (int)n, code + i + 1 + llen + llen2, (unsigned)arg_no);
i += llen + llen2 + n;
break;
}
case OP_PUSH_STR:
case OP_PUSH_DBL: {
cs_varint_decode(&code[i + 1], ~0, &n, &llen);
LOG(LL_VERBOSE_DEBUG, ("%s\t[%.*s]", buf, (int)n, code + i + 1 + llen));
print_cb(print_ctx, "%s\t[%.*s]", buf, (int)n, code + i + 1 + llen);
i += llen + n;
break;
}
Expand All @@ -187,10 +189,11 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t* code, size_t i) {
case OP_JMP_FALSE:
case OP_JMP_NEUTRAL_FALSE: {
cs_varint_decode(&code[i + 1], ~0, &n, &llen);
LOG(LL_VERBOSE_DEBUG,
("%s\t%u",
buf,
(unsigned)(i + n + llen + 1 /* becaue i will be incremented on the usual terms */)));
print_cb(
print_ctx,
"%s\t%u",
buf,
(unsigned)(i + n + llen + 1 /* becaue i will be incremented on the usual terms */));
i += llen;
break;
}
Expand All @@ -199,12 +202,13 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t* code, size_t i) {
uint64_t n1, n2;
cs_varint_decode(&code[i + 1], ~0, &n1, &l1);
cs_varint_decode(&code[i + l1 + 1], ~0, &n2, &l2);
LOG(LL_VERBOSE_DEBUG,
("%s\tB:%lu C:%lu (%d)",
buf,
(unsigned long)(i + 1 /* OP_LOOP */ + l1 + n1),
(unsigned long)(i + 1 /* OP_LOOP */ + l1 + l2 + n2),
(int)i));
print_cb(
print_ctx,
"%s\tB:%lu C:%lu (%d)",
buf,
(unsigned long)(i + 1 /* OP_LOOP */ + l1 + n1),
(unsigned long)(i + 1 /* OP_LOOP */ + l1 + l2 + n2),
(int)i);
i += l1 + l2;
break;
}
Expand Down Expand Up @@ -258,7 +262,7 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t* code, size_t i) {
case TOK_URSHIFT_ASSIGN: name = ">>>="; break;
}
/* clang-format on */
LOG(LL_VERBOSE_DEBUG, ("%s\t%s", buf, name));
print_cb(print_ctx, "%s\t%s", buf, name);
i++;
break;
}
Expand All @@ -272,28 +276,29 @@ MJS_PRIVATE size_t mjs_disasm_single(const uint8_t* code, size_t i) {
&code[i + 1 + MJS_HDR_ITEM_MAP_OFFSET * sizeof(total_size)],
sizeof(map_offset));
i += sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT;
LOG(LL_VERBOSE_DEBUG,
("%s\t[%s] end:%lu map_offset: %lu",
buf,
&code[i + 1],
(unsigned long)start + total_size,
(unsigned long)start + map_offset));
print_cb(
print_ctx,
"%s\t[%s] end:%lu map_offset: %lu",
buf,
&code[i + 1],
(unsigned long)start + total_size,
(unsigned long)start + map_offset);
i += strlen((char*)(code + i + 1)) + 1;
break;
}
default:
LOG(LL_VERBOSE_DEBUG, ("%s", buf));
print_cb(print_ctx, "%s", buf);
break;
}
return i - start_i;
}

void mjs_disasm(const uint8_t* code, size_t len) {
void mjs_disasm(const uint8_t* code, size_t len, MjsPrintCallback print_cb, void* print_ctx) {
size_t i, start = 0;
mjs_header_item_t map_offset = 0, total_size = 0;

for(i = 0; i < len; i++) {
size_t delta = mjs_disasm_single(code, i);
size_t delta = mjs_disasm_single(code, i, print_cb, print_ctx);
if(code[i] == OP_BCODE_HEADER) {
start = i;
memcpy(&total_size, &code[i + 1], sizeof(total_size));
Expand All @@ -312,38 +317,49 @@ void mjs_disasm(const uint8_t* code, size_t len) {
}
}

static void mjs_dump_obj_stack(const char* name, const struct mbuf* m, struct mjs* mjs) {
void mjs_disasm_all(struct mjs* mjs, MjsPrintCallback print_cb, void* print_ctx) {
int parts_cnt = mjs_bcode_parts_cnt(mjs);
for(int i = 0; i < parts_cnt; i++) {
struct mjs_bcode_part* bp = mjs_bcode_part_get(mjs, i);
mjs_disasm((uint8_t*)bp->data.p, bp->data.len, print_cb, print_ctx);
}
}

static void mjs_dump_obj_stack(
struct mjs* mjs,
const char* name,
const struct mbuf* m,
MjsPrintCallback print_cb,
void* print_ctx) {
char buf[50];
size_t i, n;
n = mjs_stack_size(m);
LOG(LL_VERBOSE_DEBUG, ("%12s (%d elems): ", name, (int)n));
print_cb(print_ctx, "%12s (%d elems): ", name, (int)n);
for(i = 0; i < n; i++) {
mjs_sprintf(((mjs_val_t*)m->buf)[i], mjs, buf, sizeof(buf));
LOG(LL_VERBOSE_DEBUG, ("%34s", buf));
print_cb(print_ctx, "%34s", buf);
}
}

void mjs_dump(struct mjs* mjs, int do_disasm) {
LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP BEGIN"));
mjs_dump_obj_stack("DATA_STACK", &mjs->stack, mjs);
mjs_dump_obj_stack("CALL_STACK", &mjs->call_stack, mjs);
mjs_dump_obj_stack("SCOPES", &mjs->scopes, mjs);
mjs_dump_obj_stack("LOOP_OFFSETS", &mjs->loop_addresses, mjs);
mjs_dump_obj_stack("ARG_STACK", &mjs->arg_stack, mjs);
void mjs_dump(struct mjs* mjs, int do_disasm, MjsPrintCallback print_cb, void* print_ctx) {
print_cb(print_ctx, "------- MJS VM DUMP BEGIN");
mjs_dump_obj_stack(mjs, "DATA_STACK", &mjs->stack, print_cb, print_ctx);
mjs_dump_obj_stack(mjs, "CALL_STACK", &mjs->call_stack, print_cb, print_ctx);
mjs_dump_obj_stack(mjs, "SCOPES", &mjs->scopes, print_cb, print_ctx);
mjs_dump_obj_stack(mjs, "LOOP_OFFSETS", &mjs->loop_addresses, print_cb, print_ctx);
mjs_dump_obj_stack(mjs, "ARG_STACK", &mjs->arg_stack, print_cb, print_ctx);
if(do_disasm) {
int parts_cnt = mjs_bcode_parts_cnt(mjs);
int i;
LOG(LL_VERBOSE_DEBUG, ("%23s", "CODE:"));
print_cb(print_ctx, "%23s", "CODE:");
for(i = 0; i < parts_cnt; i++) {
struct mjs_bcode_part* bp = mjs_bcode_part_get(mjs, i);
mjs_disasm((uint8_t*)bp->data.p, bp->data.len);
mjs_disasm((uint8_t*)bp->data.p, bp->data.len, print_cb, print_ctx);
}
}
LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP END"));
print_cb(print_ctx, "------- MJS VM DUMP END");
}

#endif

MJS_PRIVATE int mjs_check_arg(
struct mjs* mjs,
int arg_num,
Expand Down
10 changes: 4 additions & 6 deletions lib/mjs/mjs_util_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@
extern "C" {
#endif /* __cplusplus */

typedef void (*MjsPrintCallback)(void* ctx, const char* format, ...);

const char* mjs_typeof(mjs_val_t v);

void mjs_fprintf(mjs_val_t v, struct mjs* mjs, FILE* fp);
void mjs_sprintf(mjs_val_t v, struct mjs* mjs, char* buf, size_t buflen);

#if MJS_ENABLE_DEBUG

void mjs_disasm(const uint8_t* code, size_t len);
void mjs_dump(struct mjs* mjs, int do_disasm);

#endif
void mjs_disasm_all(struct mjs* mjs, MjsPrintCallback print_cb, void* print_ctx);
void mjs_dump(struct mjs* mjs, int do_disasm, MjsPrintCallback print_cb, void* print_ctx);

/*
* Returns the filename corresponding to the given bcode offset.
Expand Down
2 changes: 2 additions & 0 deletions targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
Expand Up @@ -1749,7 +1749,9 @@ Function,+,mjs_call,mjs_err_t,"mjs*, mjs_val_t*, mjs_val_t, mjs_val_t, int, ..."
Function,+,mjs_create,mjs*,void*
Function,+,mjs_del,int,"mjs*, mjs_val_t, const char*, size_t"
Function,+,mjs_destroy,void,mjs*
Function,-,mjs_disasm_all,void,"mjs*, MjsPrintCallback, void*"
Function,+,mjs_disown,int,"mjs*, mjs_val_t*"
Function,-,mjs_dump,void,"mjs*, int, MjsPrintCallback, void*"
Function,+,mjs_exec,mjs_err_t,"mjs*, const char*, mjs_val_t*"
Function,+,mjs_exec_file,mjs_err_t,"mjs*, const char*, mjs_val_t*"
Function,+,mjs_exit,void,mjs*
Expand Down
2 changes: 2 additions & 0 deletions targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2266,7 +2266,9 @@ Function,+,mjs_call,mjs_err_t,"mjs*, mjs_val_t*, mjs_val_t, mjs_val_t, int, ..."
Function,+,mjs_create,mjs*,void*
Function,+,mjs_del,int,"mjs*, mjs_val_t, const char*, size_t"
Function,+,mjs_destroy,void,mjs*
Function,-,mjs_disasm_all,void,"mjs*, MjsPrintCallback, void*"
Function,+,mjs_disown,int,"mjs*, mjs_val_t*"
Function,-,mjs_dump,void,"mjs*, int, MjsPrintCallback, void*"
Function,+,mjs_exec,mjs_err_t,"mjs*, const char*, mjs_val_t*"
Function,+,mjs_exec_file,mjs_err_t,"mjs*, const char*, mjs_val_t*"
Function,+,mjs_exit,void,mjs*
Expand Down