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>
This commit is contained in:
Damien George 2021-06-24 10:04:15 +10:00
parent cfd08448a1
commit c13853f4da
4 changed files with 23 additions and 56 deletions

View File

@ -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;

View File

@ -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

View File

@ -9,16 +9,6 @@ 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.
Build instructions
------------------

View File

@ -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();
}