javascript: Rework Makefile and GC so it works with latest Emscripten.

The GC now works correctly using asyncify and the functions
emscripten_scan_stack() and emscripten_scan_registers().  Stack/call depth
is monitored via the use of the pystack option.

Fixes issue #6738.

Signed-off-by: Damien George <damien@micropython.org>
pull/7449/head
Damien George 2021-06-24 10:04:15 +10:00
rodzic cfd08448a1
commit c13853f4da
4 zmienionych plików z 23 dodań i 56 usunięć

Wyświetl plik

@ -1,10 +0,0 @@
--- JSBackend.cpp 2018-01-10 16:35:07.331418145 +1100
+++ JSBackend_mp_js.cpp 2018-01-10 16:40:04.804633134 +1100
@@ -4280,6 +4280,7 @@
void JSWriter::calculateNativizedVars(const Function *F) {
NativizedVars.clear();
+ return;
for (Function::const_iterator I = F->begin(), BE = F->end(); I != BE; ++I) {
auto BI = &*I;

Wyświetl plik

@ -6,24 +6,16 @@ QSTR_DEFS = qstrdefsport.h
include $(TOP)/py/py.mk
CC = emcc -g4
LD = emcc -g4
CC = emcc
LD = emcc
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
CPP = clang -E
ifdef EMSCRIPTEN
CPP += -isystem $(EMSCRIPTEN)/system/include/libc -cxx-isystem $(EMSCRIPTEN)/system/include/libcxx
endif
CFLAGS = -m32 -Wall -Werror -Wdouble-promotion -Wfloat-conversion $(INC) -std=c99 $(COPT)
LDFLAGS = -m32 -Wl,-Map=$@.map,--cref -Wl,--gc-sections
CFLAGS += -O0 -DNDEBUG
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += -std=c99 -Wall -Werror -Wdouble-promotion -Wfloat-conversion
CFLAGS += -O3 -DNDEBUG
CFLAGS += $(INC)
ifneq ($(FROZEN_MPY_DIR),)
# To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and
@ -46,12 +38,12 @@ SRC_C = \
SRC_QSTR += $(SRC_C)
OBJ =
OBJ = $(PY_O)
OBJ += $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
JSFLAGS = -O0 -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_sched_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s "BINARYEN_TRAP_MODE='clamp'" --memory-init-file 0 --js-library library.js
JSFLAGS += -s ASYNCIFY
JSFLAGS += -s EXPORTED_FUNCTIONS="['_mp_js_init', '_mp_js_init_repl', '_mp_js_do_str', '_mp_js_process_char', '_mp_hal_get_interrupt_char', '_mp_sched_keyboard_interrupt']" -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']" -s --memory-init-file 0 --js-library library.js
all: $(BUILD)/micropython.js
@ -65,6 +57,6 @@ min: $(BUILD)/micropython.js
test: $(BUILD)/micropython.js $(TOP)/tests/run-tests.py
$(eval DIRNAME=ports/$(notdir $(CURDIR)))
cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests.py
cd $(TOP)/tests && MICROPY_MICROPYTHON=../ports/javascript/node_run.sh ./run-tests.py -j1
include $(TOP)/py/mkrules.mk

Wyświetl plik

@ -7,17 +7,7 @@ Dependencies
------------
Building micropython.js bears the same requirements as the standard MicroPython
ports with the addition of Emscripten (and uglify-js for the minified file).
A standard installation of Emscripten should provide functional code, however
if memory errors are encountered it may be worthwhile to modify the tool.
`emscripten-fastcomp/lib/Target/JSBackend.cpp` may require the minor fix
found in JSBackend.patch. This patch attempts to address situations where
C code running through Emscripten is denied access to Javascript variables
leading to false-positives in the MicroPython garbage collector as variables
with pointers exclusively in Javascript will be erased prematurely.
Refer to Emscripten documentation for instructions on building Emscripten
from source.
ports with the addition of Emscripten (and uglify-js for the minified file).
Build instructions
------------------
@ -39,15 +29,15 @@ Access the repl with:
Stack size may be modified using:
$ node build/micropython.js -X stack=64K
$ node build/micropython.js -X stack=64K
Where stack size may be represented in Bytes, KiB or MiB.
MicroPython scripts may be executed using:
$ node build/micropython.js hello.py
$ node build/micropython.js hello.py
Alternatively micropython.js may by accessed by other javascript programs in node
Alternatively micropython.js may by accessed by other javascript programs in node
using the require command and the general API outlined below. For example:
```javascript
@ -85,7 +75,7 @@ demonstrates basic functionality:
```
MicroPython code execution will suspend the browser so be sure to atomize usage
within this environment. Unfortunately interrupts have not been implemented for the
within this environment. Unfortunately interrupts have not been implemented for the
browser.
Testing
@ -124,5 +114,5 @@ the repl.
mp_js_process_char(char)
```
Input character into MicroPython repl. `char` must be of type `number`. This
Input character into MicroPython repl. `char` must be of type `number`. This
will execute MicroPython code when necessary.

Wyświetl plik

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George and 2017, 2018 Rami Ali
* Copyright (c) 2013-2021 Damien P. George and 2017, 2018 Rami Ali
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -36,6 +36,7 @@
#include "py/mperrno.h"
#include "lib/utils/pyexec.h"
#include "emscripten.h"
#include "library.h"
#if MICROPY_ENABLE_COMPILER
@ -70,8 +71,6 @@ int do_str(const char *src, mp_parse_input_kind_t input_kind) {
}
#endif
static char *stack_top;
int mp_js_do_str(const char *code) {
return do_str(code, MP_PARSE_FILE_INPUT);
}
@ -81,9 +80,6 @@ int mp_js_process_char(int c) {
}
void mp_js_init(int heap_size) {
int stack_dummy;
stack_top = (char *)&stack_dummy;
#if MICROPY_ENABLE_GC
char *heap = (char *)malloc(heap_size * sizeof(char));
gc_init(heap, heap + heap_size);
@ -105,15 +101,14 @@ void mp_js_init_repl() {
pyexec_event_repl_init();
}
STATIC void gc_scan_func(void *begin, void *end) {
gc_collect_root((void **)begin, (void **)end - (void **)begin + 1);
}
void gc_collect(void) {
// WARNING: This gc_collect implementation doesn't try to get root
// pointers from CPU registers, and thus may function incorrectly.
jmp_buf dummy;
if (setjmp(dummy) == 0) {
longjmp(dummy, 1);
}
gc_collect_start();
gc_collect_root((void *)stack_top, ((mp_uint_t)(void *)(&dummy + 1) - (mp_uint_t)stack_top) / sizeof(mp_uint_t));
emscripten_scan_stack(gc_scan_func);
emscripten_scan_registers(gc_scan_func);
gc_collect_end();
}