diff --git a/CMakeLists.txt b/CMakeLists.txt index 715e516e..b635b4c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,6 +259,7 @@ target_link_libraries(qjsc qjs) add_executable(qjs_exe gen/repl.c + gen/standalone.c qjs.c ) add_qjs_libc_if_needed(qjs_exe) diff --git a/Makefile b/Makefile index 2ec7ee4e..baeafd0e 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,7 @@ clean: codegen: $(QJSC) $(QJSC) -ss -o gen/repl.c -m repl.js + $(QJSC) -ss -o gen/standalone.c -m standalone.js $(QJSC) -e -o gen/function_source.c tests/function_source.js $(QJSC) -e -o gen/hello.c examples/hello.js $(QJSC) -e -o gen/hello_module.c -m examples/hello_module.js diff --git a/gen/standalone.c b/gen/standalone.c new file mode 100644 index 00000000..fe26518d --- /dev/null +++ b/gen/standalone.c @@ -0,0 +1,306 @@ +/* File generated automatically by the QuickJS-ng compiler. */ + +#include + +const uint32_t qjsc_standalone_size = 2369; + +const uint8_t qjsc_standalone[2369] = { + 0x13, 0x4c, 0x01, 0x1a, 0x73, 0x74, 0x61, 0x6e, + 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x2e, 0x6a, + 0x73, 0x01, 0x0e, 0x71, 0x6a, 0x73, 0x3a, 0x73, + 0x74, 0x64, 0x01, 0x0c, 0x71, 0x6a, 0x73, 0x3a, + 0x6f, 0x73, 0x01, 0x12, 0x71, 0x6a, 0x73, 0x3a, + 0x62, 0x6a, 0x73, 0x6f, 0x6e, 0x01, 0x22, 0x63, + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x53, 0x74, + 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, + 0x01, 0x1a, 0x72, 0x75, 0x6e, 0x53, 0x74, 0x61, + 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x01, + 0x06, 0x73, 0x74, 0x64, 0x01, 0x04, 0x6f, 0x73, + 0x01, 0x0a, 0x62, 0x6a, 0x73, 0x6f, 0x6e, 0x01, + 0x28, 0x4a, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, + 0x5f, 0x4f, 0x42, 0x4a, 0x5f, 0x42, 0x59, 0x54, + 0x45, 0x43, 0x4f, 0x44, 0x45, 0x01, 0x2a, 0x4a, + 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x4f, + 0x42, 0x4a, 0x5f, 0x52, 0x45, 0x46, 0x45, 0x52, + 0x45, 0x4e, 0x43, 0x45, 0x01, 0x2a, 0x4a, 0x53, + 0x5f, 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, + 0x42, 0x4a, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x43, + 0x4f, 0x44, 0x45, 0x01, 0x2c, 0x4a, 0x53, 0x5f, + 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, 0x42, + 0x4a, 0x5f, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45, + 0x4e, 0x43, 0x45, 0x01, 0x32, 0x4a, 0x53, 0x5f, + 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, 0x42, + 0x4a, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x01, 0x0e, + 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x01, + 0x16, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x41, + 0x73, 0x63, 0x69, 0x69, 0x01, 0x16, 0x64, 0x65, + 0x63, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x63, 0x69, + 0x69, 0x01, 0x06, 0x74, 0x78, 0x74, 0x01, 0x02, + 0x63, 0x01, 0x14, 0x63, 0x68, 0x61, 0x72, 0x43, + 0x6f, 0x64, 0x65, 0x41, 0x74, 0x01, 0x06, 0x6d, + 0x61, 0x70, 0x01, 0x06, 0x62, 0x75, 0x66, 0x01, + 0x18, 0x66, 0x72, 0x6f, 0x6d, 0x43, 0x68, 0x61, + 0x72, 0x43, 0x6f, 0x64, 0x65, 0x01, 0x0c, 0x69, + 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x0e, 0x6f, + 0x75, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x12, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x45, 0x78, + 0x65, 0x01, 0x04, 0x6a, 0x73, 0x01, 0x08, 0x63, + 0x6f, 0x64, 0x65, 0x01, 0x10, 0x62, 0x79, 0x74, + 0x65, 0x63, 0x6f, 0x64, 0x65, 0x01, 0x06, 0x65, + 0x78, 0x65, 0x01, 0x0e, 0x65, 0x78, 0x65, 0x53, + 0x69, 0x7a, 0x65, 0x01, 0x12, 0x6e, 0x65, 0x77, + 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x01, 0x0c, + 0x6e, 0x65, 0x77, 0x45, 0x78, 0x65, 0x01, 0x04, + 0x64, 0x77, 0x01, 0x0a, 0x6e, 0x65, 0x77, 0x46, + 0x64, 0x01, 0x10, 0x6c, 0x6f, 0x61, 0x64, 0x46, + 0x69, 0x6c, 0x65, 0x01, 0x1e, 0x66, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6f, + 0x70, 0x65, 0x6e, 0x20, 0x01, 0x14, 0x65, 0x76, + 0x61, 0x6c, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x01, 0x18, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, + 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x01, 0x1c, + 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x5f, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x01, 0x0a, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x01, 0x0a, 0x61, + 0x72, 0x67, 0x76, 0x30, 0x01, 0x0c, 0x62, 0x69, + 0x6e, 0x61, 0x72, 0x79, 0x01, 0x0c, 0x62, 0x75, + 0x66, 0x66, 0x65, 0x72, 0x01, 0x10, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x01, 0x08, + 0x53, 0x69, 0x7a, 0x65, 0x01, 0x0a, 0x4d, 0x61, + 0x67, 0x69, 0x63, 0x01, 0x12, 0x4d, 0x61, 0x67, + 0x69, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x01, 0x10, + 0x44, 0x61, 0x74, 0x61, 0x53, 0x69, 0x7a, 0x65, + 0x01, 0x12, 0x73, 0x65, 0x74, 0x55, 0x69, 0x6e, + 0x74, 0x33, 0x32, 0x01, 0x08, 0x6f, 0x70, 0x65, + 0x6e, 0x01, 0x10, 0x4f, 0x5f, 0x57, 0x52, 0x4f, + 0x4e, 0x4c, 0x59, 0x01, 0x0e, 0x4f, 0x5f, 0x43, + 0x52, 0x45, 0x41, 0x54, 0x01, 0x0e, 0x4f, 0x5f, + 0x54, 0x52, 0x55, 0x4e, 0x43, 0x01, 0x22, 0x66, + 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74, 0x6f, + 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, + 0x01, 0x14, 0x62, 0x79, 0x74, 0x65, 0x4c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x01, 0x3c, 0x66, 0x61, + 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x6f, + 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, + 0x66, 0x69, 0x6c, 0x65, 0x01, 0x0a, 0x63, 0x6c, + 0x6f, 0x73, 0x65, 0x01, 0x08, 0x66, 0x69, 0x6c, + 0x65, 0x01, 0x02, 0x72, 0x01, 0x0e, 0x74, 0x72, + 0x61, 0x69, 0x6c, 0x65, 0x72, 0x01, 0x0a, 0x6d, + 0x61, 0x67, 0x69, 0x63, 0x01, 0x0c, 0x6f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x01, 0x04, 0x72, 0x62, + 0x01, 0x36, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x20, 0x74, 0x6f, 0x20, 0x6f, 0x70, 0x65, 0x6e, + 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, + 0x62, 0x6c, 0x65, 0x3a, 0x20, 0x01, 0x08, 0x73, + 0x65, 0x65, 0x6b, 0x01, 0x10, 0x53, 0x45, 0x45, + 0x4b, 0x5f, 0x45, 0x4e, 0x44, 0x01, 0x18, 0x73, + 0x65, 0x65, 0x6b, 0x20, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x3a, 0x20, 0x01, 0x08, 0x72, 0x65, 0x61, + 0x64, 0x01, 0x40, 0x63, 0x6f, 0x72, 0x72, 0x75, + 0x70, 0x74, 0x65, 0x64, 0x20, 0x62, 0x69, 0x6e, + 0x61, 0x72, 0x79, 0x2c, 0x20, 0x6d, 0x61, 0x67, + 0x69, 0x63, 0x20, 0x6d, 0x69, 0x73, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x01, 0x12, 0x67, 0x65, 0x74, + 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x01, 0x10, + 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, + 0x01, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x01, + 0x14, 0x72, 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x01, 0x16, 0x65, 0x76, 0x61, + 0x6c, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x01, 0x10, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x6a, + 0x73, 0x32, 0x0d, 0xc0, 0x03, 0x03, 0xc2, 0x03, + 0xc4, 0x03, 0xc6, 0x03, 0x02, 0x00, 0x0b, 0xc8, + 0x03, 0x00, 0x0c, 0xca, 0x03, 0x00, 0x03, 0x00, + 0xfc, 0x01, 0x00, 0x01, 0xfc, 0x01, 0x01, 0x02, + 0xfc, 0x01, 0x02, 0x00, 0x0c, 0x20, 0x02, 0x01, + 0xa2, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x04, + 0x58, 0x00, 0xcc, 0x03, 0x00, 0x0d, 0xce, 0x03, + 0x01, 0x0d, 0xd0, 0x03, 0x02, 0x0d, 0xd2, 0x03, + 0x00, 0x0d, 0xd4, 0x03, 0x01, 0x0d, 0xd6, 0x03, + 0x02, 0x0d, 0xd8, 0x03, 0x03, 0x0d, 0xda, 0x03, + 0x04, 0x0d, 0xdc, 0x03, 0x05, 0x0d, 0xde, 0x03, + 0x06, 0x01, 0xe0, 0x03, 0x07, 0x01, 0xc8, 0x03, + 0x08, 0x01, 0xca, 0x03, 0x09, 0x01, 0x0c, 0x43, + 0x02, 0x01, 0xde, 0x03, 0x01, 0x00, 0x01, 0x05, + 0x00, 0x01, 0x1e, 0x01, 0xe2, 0x03, 0x00, 0x01, + 0x00, 0x0c, 0x42, 0x02, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x03, 0x00, 0x00, 0x0a, 0x01, 0xe4, 0x03, + 0x00, 0x01, 0x00, 0xd1, 0x42, 0xf3, 0x00, 0x00, + 0x00, 0xb4, 0x25, 0x01, 0x00, 0x38, 0xa6, 0x00, + 0x00, 0x00, 0x11, 0xd1, 0x42, 0x5e, 0x00, 0x00, + 0x00, 0xc0, 0x24, 0x01, 0x00, 0x42, 0xf4, 0x00, + 0x00, 0x00, 0xbf, 0x00, 0x24, 0x01, 0x00, 0x21, + 0x01, 0x00, 0x28, 0x0c, 0x43, 0x02, 0x01, 0xe0, + 0x03, 0x01, 0x00, 0x01, 0x03, 0x00, 0x01, 0x21, + 0x01, 0xea, 0x03, 0x00, 0x01, 0x00, 0x0c, 0x42, + 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03, 0x00, + 0x00, 0x0e, 0x01, 0xe4, 0x03, 0x00, 0x01, 0x00, + 0x38, 0x97, 0x00, 0x00, 0x00, 0x42, 0xf6, 0x00, + 0x00, 0x00, 0xd1, 0x25, 0x01, 0x00, 0x38, 0x94, + 0x00, 0x00, 0x00, 0x42, 0x7b, 0x00, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0x42, 0xf4, 0x00, 0x00, + 0x00, 0xbf, 0x00, 0x24, 0x01, 0x00, 0x42, 0x5c, + 0x00, 0x00, 0x00, 0xc0, 0x25, 0x01, 0x00, 0x0c, + 0x43, 0x02, 0x01, 0xc8, 0x03, 0x03, 0x09, 0x03, + 0x07, 0x08, 0x00, 0xcf, 0x03, 0x0c, 0xee, 0x03, + 0x00, 0x01, 0x00, 0xf0, 0x03, 0x00, 0x01, 0x00, + 0xf2, 0x03, 0x00, 0x01, 0x00, 0xf4, 0x03, 0x01, + 0x00, 0x30, 0xf6, 0x03, 0x01, 0x01, 0x30, 0xf8, + 0x03, 0x01, 0x02, 0x30, 0xfa, 0x03, 0x01, 0x03, + 0x30, 0xfc, 0x03, 0x01, 0x04, 0x30, 0xfe, 0x03, + 0x01, 0x05, 0x30, 0x80, 0x04, 0x01, 0x06, 0x30, + 0x82, 0x04, 0x01, 0x07, 0x30, 0x84, 0x04, 0x01, + 0x08, 0x30, 0xcc, 0x03, 0x00, 0x0c, 0xd0, 0x03, + 0x02, 0x0c, 0xd6, 0x03, 0x05, 0x0c, 0xd8, 0x03, + 0x06, 0x0c, 0xda, 0x03, 0x07, 0x0c, 0xdc, 0x03, + 0x08, 0x0c, 0xde, 0x03, 0x09, 0x00, 0xce, 0x03, + 0x01, 0x0c, 0x61, 0x08, 0x00, 0x61, 0x07, 0x00, + 0x61, 0x06, 0x00, 0x61, 0x05, 0x00, 0x61, 0x04, + 0x00, 0x61, 0x03, 0x00, 0x61, 0x02, 0x00, 0x61, + 0x01, 0x00, 0x61, 0x00, 0x00, 0x65, 0x00, 0x00, + 0x42, 0x03, 0x01, 0x00, 0x00, 0xd1, 0x24, 0x01, + 0x00, 0xc9, 0x62, 0x00, 0x00, 0x96, 0xea, 0x19, + 0x38, 0x95, 0x00, 0x00, 0x00, 0x11, 0x04, 0x04, + 0x01, 0x00, 0x00, 0x42, 0x5d, 0x00, 0x00, 0x00, + 0xd1, 0x24, 0x01, 0x00, 0x21, 0x01, 0x00, 0x2f, + 0x65, 0x00, 0x00, 0x42, 0x05, 0x01, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x0b, 0x0a, 0x4c, 0x06, 0x01, + 0x00, 0x00, 0x0a, 0x4c, 0x07, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xca, 0x38, 0xa6, 0x00, 0x00, + 0x00, 0x11, 0x65, 0x01, 0x00, 0x42, 0x08, 0x01, + 0x00, 0x00, 0x62, 0x01, 0x00, 0x65, 0x02, 0x00, + 0x65, 0x03, 0x00, 0xa4, 0x65, 0x04, 0x00, 0xa4, + 0x24, 0x02, 0x00, 0x21, 0x01, 0x00, 0xcb, 0x65, + 0x00, 0x00, 0x42, 0x03, 0x01, 0x00, 0x00, 0xd3, + 0x11, 0xb0, 0xea, 0x0c, 0x0e, 0x38, 0x8c, 0x00, + 0x00, 0x00, 0x41, 0x09, 0x01, 0x00, 0x00, 0x0b, + 0x0a, 0x4c, 0x0a, 0x01, 0x00, 0x00, 0x24, 0x02, + 0x00, 0xcc, 0x62, 0x03, 0x00, 0xe9, 0xc2, 0x04, + 0x62, 0x03, 0x00, 0x41, 0x0b, 0x01, 0x00, 0x00, + 0x42, 0x0c, 0x01, 0x00, 0x00, 0x62, 0x04, 0x00, + 0x62, 0x02, 0x00, 0xe9, 0x9d, 0x65, 0x05, 0x00, + 0x41, 0x0d, 0x01, 0x00, 0x00, 0x9d, 0x24, 0x01, + 0x00, 0xc2, 0x05, 0x38, 0xa6, 0x00, 0x00, 0x00, + 0x11, 0x62, 0x05, 0x00, 0x21, 0x01, 0x00, 0xc2, + 0x06, 0x62, 0x06, 0x00, 0x42, 0x43, 0x00, 0x00, + 0x00, 0x62, 0x02, 0x00, 0x62, 0x04, 0x00, 0x24, + 0x02, 0x00, 0x0e, 0x62, 0x06, 0x00, 0x42, 0x43, + 0x00, 0x00, 0x00, 0x5e, 0x06, 0x00, 0x65, 0x05, + 0x00, 0x41, 0x0e, 0x01, 0x00, 0x00, 0xef, 0x62, + 0x04, 0x00, 0x62, 0x02, 0x00, 0xe9, 0x9d, 0x24, + 0x02, 0x00, 0x0e, 0x38, 0xb0, 0x00, 0x00, 0x00, + 0x11, 0x62, 0x05, 0x00, 0x62, 0x04, 0x00, 0x62, + 0x02, 0x00, 0xe9, 0x9d, 0x65, 0x05, 0x00, 0x41, + 0x0f, 0x01, 0x00, 0x00, 0x9d, 0x65, 0x05, 0x00, + 0x41, 0x10, 0x01, 0x00, 0x00, 0x21, 0x03, 0x00, + 0xc2, 0x07, 0x62, 0x07, 0x00, 0x42, 0x11, 0x01, + 0x00, 0x00, 0xb4, 0x62, 0x04, 0x00, 0x0a, 0x24, + 0x03, 0x00, 0x0e, 0x65, 0x07, 0x00, 0x42, 0x12, + 0x01, 0x00, 0x00, 0xd2, 0x65, 0x07, 0x00, 0x41, + 0x13, 0x01, 0x00, 0x00, 0x65, 0x07, 0x00, 0x41, + 0x14, 0x01, 0x00, 0x00, 0xa4, 0x65, 0x07, 0x00, + 0x41, 0x15, 0x01, 0x00, 0x00, 0xa4, 0xbd, 0xed, + 0x01, 0x24, 0x03, 0x00, 0xc2, 0x08, 0x62, 0x08, + 0x00, 0xb4, 0xa6, 0xea, 0x19, 0x38, 0x95, 0x00, + 0x00, 0x00, 0x11, 0x04, 0x16, 0x01, 0x00, 0x00, + 0x42, 0x5d, 0x00, 0x00, 0x00, 0xd2, 0x24, 0x01, + 0x00, 0x21, 0x01, 0x00, 0x2f, 0x65, 0x07, 0x00, + 0x42, 0x08, 0x01, 0x00, 0x00, 0x62, 0x08, 0x00, + 0x62, 0x05, 0x00, 0xb4, 0x62, 0x05, 0x00, 0x41, + 0x17, 0x01, 0x00, 0x00, 0x24, 0x04, 0x00, 0xb4, + 0xa6, 0xea, 0x10, 0x38, 0x95, 0x00, 0x00, 0x00, + 0x11, 0x04, 0x18, 0x01, 0x00, 0x00, 0x21, 0x01, + 0x00, 0x2f, 0x65, 0x07, 0x00, 0x42, 0x19, 0x01, + 0x00, 0x00, 0x62, 0x08, 0x00, 0x24, 0x01, 0x00, + 0x29, 0x0c, 0x43, 0x02, 0x01, 0xca, 0x03, 0x00, + 0x09, 0x00, 0x07, 0x06, 0x00, 0x8c, 0x04, 0x09, + 0xb4, 0x04, 0x01, 0x00, 0x30, 0xfa, 0x03, 0x01, + 0x01, 0x30, 0xb6, 0x04, 0x01, 0x02, 0x20, 0xb8, + 0x04, 0x01, 0x03, 0x30, 0xba, 0x04, 0x01, 0x04, + 0x30, 0x82, 0x04, 0x01, 0x05, 0x30, 0xbc, 0x04, + 0x01, 0x06, 0x30, 0xf8, 0x03, 0x01, 0x07, 0x30, + 0xf6, 0x03, 0x01, 0x08, 0x30, 0xcc, 0x03, 0x00, + 0x0c, 0xdc, 0x03, 0x08, 0x0c, 0xe0, 0x03, 0x0a, + 0x00, 0xd0, 0x03, 0x02, 0x0c, 0xd2, 0x03, 0x03, + 0x0c, 0xd4, 0x03, 0x04, 0x0c, 0x61, 0x08, 0x00, + 0x61, 0x07, 0x00, 0x61, 0x06, 0x00, 0x61, 0x05, + 0x00, 0x61, 0x04, 0x00, 0x61, 0x03, 0x00, 0x61, + 0x02, 0x00, 0x61, 0x01, 0x00, 0x61, 0x00, 0x00, + 0x38, 0x8c, 0x00, 0x00, 0x00, 0x41, 0x09, 0x01, + 0x00, 0x00, 0xc9, 0x65, 0x00, 0x00, 0x42, 0x12, + 0x01, 0x00, 0x00, 0x62, 0x00, 0x00, 0x04, 0x1f, + 0x01, 0x00, 0x00, 0x24, 0x02, 0x00, 0xca, 0x62, + 0x01, 0x00, 0x96, 0xea, 0x1b, 0x38, 0x95, 0x00, + 0x00, 0x00, 0x11, 0x04, 0x20, 0x01, 0x00, 0x00, + 0x42, 0x5d, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x21, 0x01, 0x00, 0x2f, 0x62, + 0x01, 0x00, 0x42, 0x21, 0x01, 0x00, 0x00, 0x65, + 0x01, 0x00, 0x41, 0x0d, 0x01, 0x00, 0x00, 0x8c, + 0x65, 0x00, 0x00, 0x41, 0x22, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0xcb, 0x62, 0x02, 0x00, 0xb4, + 0xa6, 0xea, 0x1c, 0x38, 0x95, 0x00, 0x00, 0x00, + 0x11, 0x04, 0x23, 0x01, 0x00, 0x00, 0x42, 0x5d, + 0x00, 0x00, 0x00, 0x62, 0x02, 0x00, 0x8c, 0x24, + 0x01, 0x00, 0x21, 0x01, 0x00, 0x2f, 0x38, 0xa6, + 0x00, 0x00, 0x00, 0x11, 0x65, 0x01, 0x00, 0x41, + 0x0d, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0xcc, + 0x62, 0x01, 0x00, 0x42, 0x24, 0x01, 0x00, 0x00, + 0x62, 0x03, 0x00, 0x41, 0x0b, 0x01, 0x00, 0x00, + 0xb4, 0x65, 0x01, 0x00, 0x41, 0x0d, 0x01, 0x00, + 0x00, 0x24, 0x03, 0x00, 0x0e, 0x38, 0xa6, 0x00, + 0x00, 0x00, 0x11, 0x62, 0x03, 0x00, 0x41, 0x0b, + 0x01, 0x00, 0x00, 0xb4, 0x65, 0x01, 0x00, 0x41, + 0x0f, 0x01, 0x00, 0x00, 0x21, 0x03, 0x00, 0xc2, + 0x04, 0xdf, 0x62, 0x04, 0x00, 0xef, 0x65, 0x01, + 0x00, 0x41, 0x0e, 0x01, 0x00, 0x00, 0xaf, 0xea, + 0x1c, 0x62, 0x01, 0x00, 0x42, 0x19, 0x01, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x0e, 0x38, 0x95, 0x00, + 0x00, 0x00, 0x11, 0x04, 0x25, 0x01, 0x00, 0x00, + 0x21, 0x01, 0x00, 0x2f, 0x38, 0xb0, 0x00, 0x00, + 0x00, 0x11, 0x62, 0x03, 0x00, 0x41, 0x0b, 0x01, + 0x00, 0x00, 0x65, 0x01, 0x00, 0x41, 0x0f, 0x01, + 0x00, 0x00, 0x65, 0x01, 0x00, 0x41, 0x10, 0x01, + 0x00, 0x00, 0x21, 0x03, 0x00, 0xc2, 0x05, 0x62, + 0x05, 0x00, 0x42, 0x26, 0x01, 0x00, 0x00, 0xb4, + 0x0a, 0x24, 0x02, 0x00, 0xc2, 0x06, 0x38, 0xa6, + 0x00, 0x00, 0x00, 0x11, 0x62, 0x06, 0x00, 0x65, + 0x01, 0x00, 0x41, 0x0d, 0x01, 0x00, 0x00, 0x9e, + 0x21, 0x01, 0x00, 0xc2, 0x07, 0x62, 0x01, 0x00, + 0x42, 0x21, 0x01, 0x00, 0x00, 0x62, 0x06, 0x00, + 0x65, 0x00, 0x00, 0x41, 0x27, 0x01, 0x00, 0x00, + 0x24, 0x02, 0x00, 0x11, 0x63, 0x02, 0x00, 0x0e, + 0x62, 0x02, 0x00, 0xb4, 0xa6, 0xea, 0x1c, 0x38, + 0x95, 0x00, 0x00, 0x00, 0x11, 0x04, 0x23, 0x01, + 0x00, 0x00, 0x42, 0x5d, 0x00, 0x00, 0x00, 0x62, + 0x02, 0x00, 0x8c, 0x24, 0x01, 0x00, 0x21, 0x01, + 0x00, 0x2f, 0x62, 0x01, 0x00, 0x42, 0x24, 0x01, + 0x00, 0x00, 0x62, 0x07, 0x00, 0x41, 0x0b, 0x01, + 0x00, 0x00, 0xb4, 0x62, 0x07, 0x00, 0xe9, 0x24, + 0x03, 0x00, 0x0e, 0x62, 0x01, 0x00, 0x42, 0x28, + 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0xea, 0x10, + 0x38, 0x95, 0x00, 0x00, 0x00, 0x11, 0x04, 0x29, + 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x2f, 0x62, + 0x01, 0x00, 0x42, 0x19, 0x01, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x0e, 0x65, 0x03, 0x00, 0x42, 0x24, + 0x01, 0x00, 0x00, 0x62, 0x07, 0x00, 0x41, 0x0b, + 0x01, 0x00, 0x00, 0xb4, 0x62, 0x07, 0x00, 0xe9, + 0x65, 0x04, 0x00, 0x65, 0x05, 0x00, 0xa4, 0x24, + 0x04, 0x00, 0xc2, 0x08, 0x65, 0x00, 0x00, 0x42, + 0x05, 0x01, 0x00, 0x00, 0x62, 0x08, 0x00, 0x0b, + 0x0a, 0x4c, 0x2a, 0x01, 0x00, 0x00, 0x25, 0x02, + 0x00, 0x08, 0xea, 0x16, 0xbf, 0x00, 0x5f, 0x09, + 0x00, 0xbf, 0x01, 0x5f, 0x0a, 0x00, 0xbf, 0x02, + 0x5f, 0x0b, 0x00, 0xbf, 0x03, 0x5f, 0x0c, 0x00, + 0x29, 0xb5, 0xb4, 0x9f, 0xe4, 0xb5, 0xb7, 0x9f, + 0x5f, 0x04, 0x00, 0xb5, 0xb4, 0x9f, 0x5f, 0x05, + 0x00, 0xb5, 0xb7, 0x9f, 0x5f, 0x06, 0x00, 0xb5, + 0xb8, 0x9f, 0x5f, 0x07, 0x00, 0x0b, 0x04, 0x2b, + 0x01, 0x00, 0x00, 0x4c, 0x0e, 0x01, 0x00, 0x00, + 0xbc, 0x08, 0x4c, 0x0f, 0x01, 0x00, 0x00, 0xb8, + 0x4c, 0x10, 0x01, 0x00, 0x00, 0xbc, 0x0c, 0x4c, + 0x0d, 0x01, 0x00, 0x00, 0x5f, 0x08, 0x00, 0x06, + 0x2e, +}; + diff --git a/qjs.c b/qjs.c index 40275ba7..e0e15a59 100644 --- a/qjs.c +++ b/qjs.c @@ -45,11 +45,67 @@ extern const uint8_t qjsc_repl[]; extern const uint32_t qjsc_repl_size; +extern const uint8_t qjsc_standalone[]; +extern const uint32_t qjsc_standalone_size; static int qjs__argc; static char **qjs__argv; +static BOOL is_standalone(const char *exe) +{ + // Must match standalone.js + static const char trailer_magic[] = "quickjs2"; + static const int trailer_magic_size = sizeof(trailer_magic) - 1; + static const int trailer_size = 12; /* 8 bytes for the trailer magic + 4 bytes for the offset. */ + + FILE *exe_f = fopen(exe, "rb"); + if (!exe_f) { + perror(exe); + exit(1); + } + if (fseek(exe_f, -trailer_size, SEEK_END) < 0) { + exit(1); + } + uint8_t buf[trailer_size]; + if (fread(buf, 1, trailer_size, exe_f) != trailer_size) { + perror("fread exe trailer"); + exit(1); + } + fclose(exe_f); + + return !memcmp(buf, trailer_magic, trailer_magic_size); +} + +static JSValue load_standalone_module(JSContext *ctx) +{ + JSModuleDef *m; + JSValue obj, val; + obj = JS_ReadObject(ctx, qjsc_standalone, qjsc_standalone_size, JS_READ_OBJ_BYTECODE); + if (JS_IsException(obj)) + goto exception; + assert(JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE); + if (JS_ResolveModule(ctx, obj) < 0) { + JS_FreeValue(ctx, obj); + goto exception; + } + js_module_set_import_meta(ctx, obj, FALSE, TRUE); + val = JS_EvalFunction(ctx, JS_DupValue(ctx, obj)); + val = js_std_await(ctx, val); + + if (JS_IsException(val)) { + JS_FreeValue(ctx, obj); + exception: + js_std_dump_error(ctx); + exit(1); + } + JS_FreeValue(ctx, val); + + m = JS_VALUE_GET_PTR(obj); + JS_FreeValue(ctx, obj); + return JS_GetModuleNamespace(ctx, m); +} + static int eval_buf(JSContext *ctx, const void *buf, int buf_len, const char *filename, int eval_flags) { @@ -333,6 +389,9 @@ void help(void) "-T --trace trace memory allocation\n" "-d --dump dump the memory usage stats\n" "-D --dump-flags flags for dumping debug data (see DUMP_* defines)\n" + "-c --compile FILE compile the given JS file as a standalone executable\n" + "-o --out FILE output file for standalone executables\n" + "--exe select the executable to use as the base, defaults to the current one\n" " --memory-limit n limit the memory usage to 'n' Kbytes\n" " --stack-size n limit the stack size to 'n' Kbytes\n" " --unhandled-rejection dump unhandled promise rejections\n" @@ -346,9 +405,13 @@ int main(int argc, char **argv) JSContext *ctx; JSValue ret; struct trace_malloc_data trace_data = { NULL }; - int optind; + int optind = 1; + char *compile_file = NULL; + char *exe = NULL; char *expr = NULL; char *dump_flags_str = NULL; + char *out = NULL; + int standalone = 0; int interactive = 0; int dump_memory = 0; int dump_flags = 0; @@ -366,12 +429,16 @@ int main(int argc, char **argv) qjs__argc = argc; qjs__argv = argv; + if (is_standalone(argv[0])) { + standalone = 1; + goto start; + } + dump_flags_str = getenv("QJS_DUMP_FLAGS"); dump_flags = dump_flags_str ? strtol(dump_flags_str, NULL, 16) : 0; /* cannot use getopt because we want to pass the command line to the script */ - optind = 1; while (optind < argc && *argv[optind] == '-') { char *arg = argv[optind] + 1; const char *longopt = ""; @@ -482,6 +549,39 @@ int main(int argc, char **argv) stack_size = parse_limit(opt_arg); break; } + if (opt == 'c' || !strcmp(longopt, "compile")) { + if (!opt_arg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing file for -c\n"); + exit(2); + } + opt_arg = argv[optind++]; + } + compile_file = opt_arg; + break; + } + if (opt == 'o' || !strcmp(longopt, "out")) { + if (!opt_arg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing file for -o\n"); + exit(2); + } + opt_arg = argv[optind++]; + } + out = opt_arg; + break; + } + if (!strcmp(longopt, "exe")) { + if (!opt_arg) { + if (optind >= argc) { + fprintf(stderr, "qjs: missing file for --exe\n"); + exit(2); + } + opt_arg = argv[optind++]; + } + exe = opt_arg; + break; + } if (opt) { fprintf(stderr, "qjs: unknown option '-%c'\n", opt); } else { @@ -491,6 +591,11 @@ int main(int argc, char **argv) } } + if (compile_file && !out) + help(); + +start: + if (trace_memory) { js_trace_malloc_init(&trace_data); rt = JS_NewRuntime2(&trace_mf, &trace_data); @@ -547,11 +652,33 @@ int main(int argc, char **argv) goto fail; } - if (expr) { + if (standalone) { + JSValue ns = load_standalone_module(ctx); + if (JS_IsException(ns)) + goto fail; + JSValue func = JS_GetPropertyStr(ctx, ns, "runStandalone"); + if (JS_IsException(ns)) + goto fail; + ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL); + } else if (compile_file) { + JSValue ns = load_standalone_module(ctx); + if (JS_IsException(ns)) + goto fail; + JSValue func = JS_GetPropertyStr(ctx, ns, "compileStandalone"); + if (JS_IsException(ns)) + goto fail; + JSValue args[3]; + args[0] = JS_NewString(ctx, compile_file); + args[1] = JS_NewString(ctx, out); + args[2] = JS_NewString(ctx, exe != NULL ? exe : argv[0]); + ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args); + JS_FreeValue(ctx, args[0]); + JS_FreeValue(ctx, args[1]); + JS_FreeValue(ctx, args[2]); + } else if (expr) { if (eval_buf(ctx, expr, strlen(expr), "", 0)) goto fail; - } else - if (optind >= argc) { + } else if (optind >= argc) { /* interactive mode */ interactive = 1; } else { @@ -563,7 +690,16 @@ int main(int argc, char **argv) if (interactive) { js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0); } - ret = js_std_loop(ctx); + if (standalone || compile_file) { + if (JS_IsException(ret)) { + ret = JS_GetException(ctx); + } else { + JS_FreeValue(ctx, ret); + ret = js_std_loop(ctx); + } + } else { + ret = js_std_loop(ctx); + } if (!JS_IsUndefined(ret)) { js_std_dump_error1(ctx, ret); JS_FreeValue(ctx, ret); diff --git a/standalone.js b/standalone.js new file mode 100644 index 00000000..62cfb935 --- /dev/null +++ b/standalone.js @@ -0,0 +1,120 @@ +import * as std from "qjs:std"; +import * as os from "qjs:os"; +import * as bjson from "qjs:bjson"; + +// See quickjs.h +const JS_READ_OBJ_BYTECODE = 1 << 0; +const JS_READ_OBJ_REFERENCE = 1 << 3; +const JS_WRITE_OBJ_BYTECODE = 1 << 0; +const JS_WRITE_OBJ_REFERENCE = 1 << 3; +const JS_WRITE_OBJ_STRIP_SOURCE = 1 << 4; + +/** + * Trailer for standalone binaries. When some code gets bundled with the qjs + * executable we add a 12 byte trailer. The first 8 bytes are the magic + * string that helps us understand this is a standalone binary, and the + * remaining 4 are the offset (from the beginning of the binary) where the + * bundled data is located. + * + * The offset is stored as a 32bit little-endian number. + */ +const Trailer = { + Magic: 'quickjs2', + MagicSize: 8, + DataSize: 4, + Size: 12 +}; + +function encodeAscii(txt) { + return new Uint8Array(txt.split('').map(c => c.charCodeAt(0))); +} + +function decodeAscii(buf) { + return Array.from(buf).map(c => String.fromCharCode(c)).join('') +} + +export function compileStandalone(inFile, outFile, targetExe) { + // Step 1: compile the source file to bytecode + const js = std.loadFile(inFile); + + if (!js) { + throw new Error(`failed to open ${inFile}`); + } + + const code = std.evalScript(js, { + compile_only: true, + compile_module: true + }); + const bytecode = new Uint8Array(bjson.write(code, JS_WRITE_OBJ_BYTECODE | JS_WRITE_OBJ_REFERENCE | JS_WRITE_OBJ_STRIP_SOURCE)); + + // Step 2: copy the bytecode to the end of the executable and add a marker. + const exe = std.loadFile(targetExe ?? globalThis.argv0, { binary: true }); + const exeSize = exe.length; + const newBuffer = exe.buffer.transfer(exeSize + bytecode.length + Trailer.Size); + const newExe = new Uint8Array(newBuffer); + + newExe.set(bytecode, exeSize); + newExe.set(encodeAscii(Trailer.Magic), exeSize + bytecode.length); + + const dw = new DataView(newBuffer, exeSize + bytecode.length + Trailer.MagicSize, Trailer.DataSize); + + dw.setUint32(0, exeSize, true /* little-endian */); + + // We use os.open() so we can set the permissions mask. + const newFd = os.open(outFile, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o755); + + if (newFd < 0) { + throw new Error(`failed to create ${outFile}`); + } + if (os.write(newFd, newBuffer, 0, newBuffer.byteLength) < 0) { + throw new Error(`failed to write to output file`); + } + os.close(newFd); +} + +export function runStandalone() { + const file = globalThis.argv0; + const exe = std.open(file, 'rb'); + + if (!exe) { + throw new Error(`failed to open executable: ${file}`); + } + + let r = exe.seek(-Trailer.Size, std.SEEK_END); + if (r < 0) { + throw new Error(`seek error: ${-r}`); + } + + const trailer = new Uint8Array(Trailer.Size); + + exe.read(trailer.buffer, 0, Trailer.Size); + + const magic = new Uint8Array(trailer.buffer, 0, Trailer.MagicSize); + + // Shouldn't happen since qjs.c checks for it. + if (decodeAscii(magic) !== Trailer.Magic) { + exe.close(); + throw new Error('corrupted binary, magic mismatch'); + } + + const dw = new DataView(trailer.buffer, Trailer.MagicSize, Trailer.DataSize); + const offset = dw.getUint32(0, true /* little-endian */); + const bytecode = new Uint8Array(offset - Trailer.Size); + + r = exe.seek(offset, std.SEEK_SET); + if (r < 0) { + throw new Error(`seek error: ${-r}`); + } + + exe.read(bytecode.buffer, 0, bytecode.length); + if (exe.error()) { + throw new Error('read error'); + } + exe.close(); + + const code = bjson.read(bytecode.buffer, 0, bytecode.length, JS_READ_OBJ_BYTECODE | JS_READ_OBJ_REFERENCE); + + return std.evalScript(code, { + eval_module: true + }); +}