Add strip option in qjsc to reduce object size (#388)

- `-s` strips the source code
- `-ss` strips source and line/column numbers information
- `qjsc repl.js` generates an object size of **105726** bytes
- `qjsc -s repl.js` generates an object size of **20853** bytes
- `qjsc -ss repl.js` generates an object size of only **16147** bytes
- compile repl.js with `-ss`
- bump byte code version to 12
This commit is contained in:
Charlie Gordon 2024-04-19 08:41:12 +02:00 committed by GitHub
parent 43dc65d605
commit f326a7a195
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1362 additions and 12529 deletions

View file

@ -61,7 +61,7 @@ clean:
cmake --build $(BUILD_DIR) --target clean
codegen: $(QJSC)
$(QJSC) -o gen/repl.c -m repl.js
$(QJSC) -ss -o gen/repl.c -m repl.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

View file

@ -5,7 +5,7 @@
const uint32_t qjsc_function_source_size = 384;
const uint8_t qjsc_function_source[384] = {
0x0b, 0x06, 0x0c, 0x61, 0x63, 0x74, 0x75, 0x61,
0x0c, 0x06, 0x0c, 0x61, 0x63, 0x74, 0x75, 0x61,
0x6c, 0x02, 0x66, 0x30, 0x74, 0x65, 0x73, 0x74,
0x73, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63,
@ -15,12 +15,12 @@ const uint8_t qjsc_function_source[384] = {
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 0x32, 0x20,
0x7d, 0x0c, 0x00, 0x02, 0x01, 0x9e, 0x01, 0x00,
0x7d, 0x0c, 0x00, 0xfa, 0x01, 0x9e, 0x01, 0x00,
0x06, 0x00, 0x03, 0x00, 0x01, 0xa0, 0x01, 0x06,
0xa0, 0x01, 0x00, 0x00, 0x00, 0xb2, 0x03, 0x02,
0x00, 0x30, 0xb4, 0x03, 0x04, 0x00, 0x70, 0xb2,
0x03, 0x04, 0x03, 0x70, 0x10, 0x00, 0x01, 0x00,
0xe0, 0x01, 0x00, 0x01, 0x00, 0x0c, 0x43, 0x02,
0xe0, 0x01, 0x00, 0x01, 0x00, 0x0c, 0x43, 0xfa,
0x01, 0xb4, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x03, 0x00, 0xbb, 0x2a, 0x28, 0xb6, 0x03,
0x03, 0x01, 0x04, 0x02, 0x1e, 0x0c, 0x0e, 0x1a,

View file

@ -5,12 +5,12 @@
const uint32_t qjsc_hello_size = 89;
const uint8_t qjsc_hello[89] = {
0x0b, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
0x0c, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48,
0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72,
0x6c, 0x64, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
0x6f, 0x2e, 0x6a, 0x73, 0x0c, 0x00, 0x02, 0x00,
0x6f, 0x2e, 0x6a, 0x73, 0x0c, 0x00, 0xfa, 0x00,
0x9e, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
0x14, 0x01, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x38,
0xd9, 0x00, 0x00, 0x00, 0x42, 0xda, 0x00, 0x00,

View file

@ -5,14 +5,14 @@
const uint32_t qjsc_fib_module_size = 310;
const uint8_t qjsc_fib_module[310] = {
0x0b, 0x03, 0x2c, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x0c, 0x03, 0x2c, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62, 0x5f,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x6a,
0x73, 0x06, 0x66, 0x69, 0x62, 0x02, 0x6e, 0x0d,
0xb2, 0x03, 0x00, 0x01, 0x00, 0x00, 0xb4, 0x03,
0x00, 0x00, 0x0c, 0x20, 0x02, 0x01, 0x9e, 0x01,
0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e, 0x01,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x00,
0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0x02, 0x01,
0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0xfa, 0x01,
0xb4, 0x03, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00,
0x1a, 0x01, 0xb6, 0x03, 0x00, 0x01, 0x00, 0xb4,
0x03, 0x00, 0x00, 0xd0, 0xb3, 0xa7, 0xe9, 0x03,
@ -49,7 +49,7 @@ const uint8_t qjsc_fib_module[310] = {
const uint32_t qjsc_hello_module_size = 177;
const uint8_t qjsc_hello_module[177] = {
0x0b, 0x07, 0x30, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x0c, 0x07, 0x30, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x2e, 0x6a, 0x73, 0x1e, 0x2e, 0x2f, 0x66, 0x69,
@ -60,7 +60,7 @@ const uint8_t qjsc_hello_module[177] = {
0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x10,
0x66, 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d,
0x0d, 0xb2, 0x03, 0x01, 0xb4, 0x03, 0x00, 0x00,
0x01, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x20, 0x02,
0x01, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x20, 0xfa,
0x01, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01,
0x00, 0x32, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x08,
0xe9, 0x02, 0x29, 0x38, 0xdc, 0x00, 0x00, 0x00,

13803
gen/repl.c

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
const uint32_t qjsc_test_fib_size = 166;
const uint8_t qjsc_test_fib[166] = {
0x0b, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x0c, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x10,
0x2e, 0x2f, 0x66, 0x69, 0x62, 0x2e, 0x73, 0x6f,
@ -15,7 +15,7 @@ const uint8_t qjsc_test_fib[166] = {
0x6f, 0x72, 0x6c, 0x64, 0x10, 0x66, 0x69, 0x62,
0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 0xb2, 0x03,
0x01, 0xb4, 0x03, 0x00, 0x00, 0x01, 0x00, 0xb6,
0x03, 0x00, 0x0c, 0x20, 0x02, 0x01, 0x9e, 0x01,
0x03, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e, 0x01,
0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32, 0x00,
0xb6, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02, 0x29,
0x38, 0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd, 0x00,

17
qjsc.c
View file

@ -56,7 +56,7 @@ static namelist_t cmodule_list;
static namelist_t init_module_list;
static FILE *outfile;
static const char *c_ident_prefix = "qjsc_";
static int strip;
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
int flags)
@ -155,8 +155,15 @@ static void output_object_code(JSContext *ctx,
{
uint8_t *out_buf;
size_t out_buf_len;
int flags = JS_WRITE_OBJ_BYTECODE;
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, JS_WRITE_OBJ_BYTECODE);
if (strip) {
flags |= JS_WRITE_OBJ_STRIP_SOURCE;
if (strip > 1)
flags |= JS_WRITE_OBJ_STRIP_DEBUG;
}
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
if (!out_buf) {
js_std_dump_error(ctx);
exit(1);
@ -354,6 +361,7 @@ int main(int argc, char **argv)
cname = NULL;
module = -1;
verbose = 0;
strip = 0;
stack_size = 0;
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
@ -362,7 +370,7 @@ int main(int argc, char **argv)
namelist_add(&cmodule_list, "os", "os", 0);
for(;;) {
c = getopt(argc, argv, "ho:N:mxevM:p:S:D:");
c = getopt(argc, argv, "ho:N:mxesvM:p:S:D:");
if (c == -1)
break;
switch(c) {
@ -399,6 +407,9 @@ int main(int argc, char **argv)
case 'D':
namelist_add(&dynamic_module_list, optarg, NULL, 0);
break;
case 's':
strip++;
break;
case 'v':
verbose++;
break;

View file

@ -32601,7 +32601,7 @@ typedef enum BCTagEnum {
BC_TAG_OBJECT_REFERENCE,
} BCTagEnum;
#define BC_VERSION 11
#define BC_VERSION 12
typedef struct BCWriterState {
JSContext *ctx;
@ -32609,6 +32609,8 @@ typedef struct BCWriterState {
BOOL allow_bytecode : 8;
BOOL allow_sab : 8;
BOOL allow_reference : 8;
BOOL allow_source : 1;
BOOL allow_debug : 1;
uint32_t first_atom;
uint32_t *atom_to_idx;
int atom_to_idx_size;
@ -32971,6 +32973,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValue obj)
bc_set_flags(&flags, &idx, b->super_allowed, 1);
bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
bc_set_flags(&flags, &idx, s->allow_debug, 1);
assert(idx <= 16);
bc_put_u16(s, flags);
bc_put_u8(s, b->js_mode);
@ -33027,13 +33030,19 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValue obj)
if (JS_WriteFunctionBytecode(s, b))
goto fail;
bc_put_atom(s, b->filename);
bc_put_leb128(s, b->line_num);
bc_put_leb128(s, b->col_num);
bc_put_leb128(s, b->pc2line_len);
dbuf_put(&s->dbuf, b->pc2line_buf, b->pc2line_len);
bc_put_leb128(s, b->source_len);
dbuf_put(&s->dbuf, b->source, b->source_len);
if (s->allow_debug) {
bc_put_atom(s, b->filename);
bc_put_leb128(s, b->line_num);
bc_put_leb128(s, b->col_num);
bc_put_leb128(s, b->pc2line_len);
dbuf_put(&s->dbuf, b->pc2line_buf, b->pc2line_len);
if (s->allow_source && b->source) {
bc_put_leb128(s, b->source_len);
dbuf_put(&s->dbuf, b->source, b->source_len);
} else {
bc_put_leb128(s, 0);
}
}
return 0;
fail:
return -1;
@ -33409,6 +33418,8 @@ uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValue obj,
s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
s->allow_source = ((flags & JS_WRITE_OBJ_STRIP_SOURCE) == 0);
s->allow_debug = ((flags & JS_WRITE_OBJ_STRIP_DEBUG) == 0);
/* XXX: could use a different version when bytecode is included */
if (s->allow_bytecode)
s->first_atom = JS_ATOM_END;
@ -33864,7 +33875,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
JSValue obj = JS_UNDEFINED;
uint16_t v16;
uint8_t v8;
int idx, i, local_count;
int idx, i, local_count, has_debug_info;
int function_size, cpool_offset, byte_code_offset;
int closure_var_offset, vardefs_offset;
uint32_t ic_len;
@ -33887,6 +33898,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
bc.super_allowed = bc_get_flags(v16, &idx, 1);
bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
has_debug_info = bc_get_flags(v16, &idx, 1);
if (bc_get_u8(s, &v8))
goto fail;
bc.js_mode = v8;
@ -34041,6 +34053,9 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
goto fail;
bc_read_trace(s, "}\n");
}
if (!has_debug_info)
goto nodebug;
/* read optional debug information */
bc_read_trace(s, "debug {\n");
if (bc_get_atom(s, &b->filename))
@ -34078,8 +34093,11 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
goto fail;
}
bc_read_trace(s, "}\n");
nodebug:
b->realm = JS_DupContext(ctx);
return obj;
fail:
JS_FreeAtom(ctx, bc.func_name);
JS_FreeValue(ctx, obj);
@ -36510,7 +36528,8 @@ static JSValue js_function_toString(JSContext *ctx, JSValue this_val,
p = JS_VALUE_GET_OBJ(this_val);
if (js_class_has_bytecode(p->class_id)) {
JSFunctionBytecode *b = p->u.func.function_bytecode;
return JS_NewStringLen(ctx, b->source, b->source_len);
if (b->source)
return JS_NewStringLen(ctx, b->source, b->source_len);
}
{
JSValue name;

View file

@ -816,9 +816,9 @@ JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */
#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to
encode arbitrary object
graph */
#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to encode arbitrary object graph */
#define JS_WRITE_OBJ_STRIP_SOURCE (1 << 4) /* do not write source code information */
#define JS_WRITE_OBJ_STRIP_DEBUG (1 << 5) /* do not write debug information */
JS_EXTERN uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValue obj, int flags);
JS_EXTERN uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValue obj,
int flags, uint8_t ***psab_tab, size_t *psab_tab_len);