Commit f6e8be64 authored by Camil Staps's avatar Camil Staps 🍃

Shrink prelinked bytecode further using sign bits for the variable-width encoding

parent 426be5d2
Pipeline #26086 passed with stages
in 13 minutes and 16 seconds
......@@ -158,8 +158,9 @@
(local $i i32)
(local $byte i64)
(local $result i64)
(local $val i64)
(local $shift i64)
(local $neg i32)
(local.set $len (local.get $ptr))
(local.set $i (i32.const 0))
......@@ -170,18 +171,27 @@
(local.set $ptr (i32.add (local.get $ptr) (i32.const 4)))
(loop $decode
(local.set $result (i64.const 0))
(local.set $shift (i64.const 0))
(loop $lp
(local.set $byte (i64.load8_u (local.get $ptr)))
(local.set $result (i64.or (local.get $result)
(i64.shl (i64.and (local.get $byte) (i64.const 0x7f)) (local.get $shift))))
(local.set $shift (i64.add (local.get $shift) (i64.const 7)))
(local.set $ptr (i32.add (local.get $ptr) (i32.const 1)))
(br_if $lp (i32.wrap_i64 (i64.and (local.get $byte) (i64.const 0x80))))
(local.set $byte (i64.load8_u (local.get $ptr)))
(local.set $val (i64.and (local.get $byte) (i64.const 0x3f)))
(local.set $neg (i32.wrap_i64 (i64.and (local.get $byte) (i64.const 0x40))))
(local.set $shift (i64.const -1))
(block $end-value
(loop $lp
(local.set $ptr (i32.add (local.get $ptr) (i32.const 1)))
(br_if $end-value (i32.eqz (i32.wrap_i64 (i64.and (local.get $byte) (i64.const 0x80)))))
(local.set $shift (i64.add (local.get $shift) (i64.const 7)))
(local.set $byte (i64.load8_u (local.get $ptr)))
(local.set $val (i64.or (local.get $val)
(i64.shl (i64.and (local.get $byte) (i64.const 0x7f)) (local.get $shift))))
(br $lp)
)
)
(if
(local.get $neg)
(then (local.set $val (i64.sub (i64.const 0) (local.get $val))))
)
(i64.store (local.get $i) (local.get $result))
(i64.store (local.get $i) (local.get $val))
(local.set $i (i32.add (local.get $i) (i32.const 8)))
(br_if $decode (local.tee $section-len (i32.sub (local.get $section-len) (i32.const 1))))
......
......@@ -28,7 +28,6 @@ class ABCInterpreter {
// Just to setup properties. New instances should be created with the static
// method instantiate() below.
constructor () {
this.prog=null;
this.memory=null;
this.memory_array=null;
......@@ -447,18 +446,18 @@ class ABCInterpreter {
return words_needed;
};
me.prog=new Uint32Array(bytecode);
bytecode=new Uint32Array(bytecode);
me.words_needed=parse_prelinked_bytecode(me.prog);
me.words_needed_for_program=parse_prelinked_bytecode(bytecode);
var data_size=me.stack_size+me.heap_size*2;
if (data_size<me.prog.length/4)
data_size=me.prog.length/4;
const blocks_needed=Math.floor((me.words_needed*8 + data_size + 65535) / 65536);
if (data_size<bytecode.length/4)
data_size=bytecode.length/4;
const blocks_needed=Math.floor((me.words_needed_for_program*8 + data_size + 65535) / 65536);
me.memory=new WebAssembly.Memory({initial: blocks_needed});
me.memory_array=new Uint32Array(me.memory.buffer);
parse_prelinked_bytecode(me.prog, new Uint32Array(me.memory.buffer,me.words_needed*8));
parse_prelinked_bytecode(bytecode, new Uint32Array(me.memory.buffer,me.words_needed_for_program*8));
const util_imports={
clean: {
......@@ -514,8 +513,7 @@ class ABCInterpreter {
}).then(function(util){
me.util=util;
me.util.instance.exports.decode_prelinked_bytecode(me.words_needed*8);
delete me.words_needed;
me.util.instance.exports.decode_prelinked_bytecode(me.words_needed_for_program*8);
const interpreter_imports={
clean: {
......@@ -625,7 +623,8 @@ class ABCInterpreter {
}).then(function(intp){
me.interpreter=intp;
const asp=4*me.prog.length;
const asp=Math.floor((me.words_needed_for_program*8+7)/8)*8;
delete me.words_needed_for_program;
const bsp=asp+me.stack_size;
const csp=asp+me.stack_size/2;
const hp=bsp+8;
......@@ -683,8 +682,6 @@ class ABCInterpreter {
me.interpreter.instance.exports.set_asp(old_asp);
};
delete me.prog;
return me;
});
}
......
......@@ -92,7 +92,7 @@ void write_section(FILE *f, enum section_type type, uint32_t len, uint64_t *data
fwrite(data, sizeof(uint64_t), len, f);
}
uint32_t leb128_encode(uint32_t len, uint64_t *data, uint64_t **dest) {
static uint32_t varwidth_encode(uint32_t len, uint64_t *data, uint64_t **dest) {
char *ptr=safe_malloc (len*sizeof(uint64_t)*5/4); /* rough upper bound */
*dest=(uint64_t*)ptr;
......@@ -101,21 +101,34 @@ uint32_t leb128_encode(uint32_t len, uint64_t *data, uint64_t **dest) {
while (len--) {
uint64_t val=*data++;
do {
char byte=val&0x7f;
char byte=0x00;
if ((int64_t)val<0) {
val=0-(int64_t)val;
byte=0x40;
}
byte|=val&0x3f;
val>>=6;
if (val)
byte|=0x80;
*ptr++=byte;
while (val) {
byte=val&0x7f;
val>>=7;
if (val)
byte|=0x80;
*ptr++=byte;
} while (val);
}
}
return ((ptr-(char*)*dest)+7)>>3;
}
void write_section_leb128(FILE *f, enum section_type type, uint32_t len, uint64_t *data) {
static void write_section_varwidth(FILE *f, enum section_type type, uint32_t len, uint64_t *data) {
uint64_t *leb_encoded_data;
uint32_t leb_encoded_len=leb128_encode (len,data,&leb_encoded_data);
uint32_t leb_encoded_len=varwidth_encode (len,data,&leb_encoded_data);
write_section (f,type,leb_encoded_len,leb_encoded_data);
free (leb_encoded_data);
}
......@@ -167,9 +180,9 @@ int main(int argc, char **argv) {
struct program *program=state.program;
prepare_preamble();
write_section_leb128(output_file, ST_Preamble, sizeof(prelinker_preamble)/sizeof(uint64_t), prelinker_preamble);
write_section_leb128(output_file, ST_Code, program->code_size, program->code);
write_section_leb128(output_file, ST_Data, program->data_size, program->data);
write_section_varwidth(output_file, ST_Preamble, sizeof(prelinker_preamble)/sizeof(uint64_t), prelinker_preamble);
write_section_varwidth(output_file, ST_Code, program->code_size, program->code);
write_section_varwidth(output_file, ST_Data, program->data_size, program->data);
write_section(output_file, ST_Start, 1, &program->symbol_table[program->start_symbol_id].offset);
fclose(output_file);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment