Verified Commit 0f07f2c2 authored by Camil Staps's avatar Camil Staps 🚀

Use unsigned LEB128 encoding in prelinker (saveas roughly 50%)

parent 764f8258
Pipeline #26020 failed with stages
in 7 minutes and 34 seconds
......@@ -151,6 +151,47 @@
)
)
(func (export "decode_prelinked_bytecode") (param $ptr i32)
(local $section-len i32)
(local $len i32)
(local $i i32)
(local $byte i64)
(local $result i64)
(local $shift i64)
(local.set $len (local.get $ptr))
(local.set $i (i32.const 0))
(loop $sections
(local.set $section-len (i32.load (local.get $ptr)))
(if (i32.eqz (local.get $section-len)) (return))
(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))))
)
(i64.store (local.get $i) (local.get $result))
(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))))
)
(local.set $ptr (i32.and (i32.add (local.get $ptr) (i32.const 7)) (i32.const 0xfffffff8)))
(br $sections)
)
)
(func (export "gc") (param $asp i32)
(local $old i32)
(local $new i32)
......
......@@ -417,24 +417,47 @@ class ABCInterpreter {
throw new ABCError('failed to fetch bytecode');
return resp.arrayBuffer();
}).then(function(bytecode){
const parse_prelinked_bytecode=function (prog, to_array=null) {
var prog_offset=0;
var words_needed=0;
while (prog.length>0) {
switch (prog[0]) {
case 1: /* ST_Code */
me.code_offset=words_needed;
case 0: /* ST_Preamble */
case 2: /* ST_Data */
const words_in_section=prog[1]*2;
if (to_array!=null)
for (var k=0; k<words_in_section; k++)
to_array[prog_offset+k]=prog[k+2];
prog_offset+=words_in_section;
words_needed+=prog[2];
break;
case 3: /* ST_Start: ignore */
break;
default:
throw new ABCError ('could not parse bytecode');
}
prog=prog.slice(2+2*prog[1]);
}
return words_needed;
};
me.prog=new Uint32Array(bytecode);
const blocks_needed=Math.floor((me.prog.length*4 + me.stack_size + me.heap_size*2 + 65535) / 65536);
me.words_needed=parse_prelinked_bytecode(me.prog);
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);
me.memory=new WebAssembly.Memory({initial: blocks_needed});
me.memory_array=new Uint32Array(me.memory.buffer);
for (var i=0; i<me.prog.length; i++)
me.memory_array[i]=me.prog[i];
(function(prog){
var i=0;
while (prog.length > 0) {
if (prog[0]==1) /* ST_Code section; see bcprelink.c */
me.code_offset=i+1;
i+=1+prog[1];
prog=prog.slice(2+2*prog[1]);
}
})(me.prog);
parse_prelinked_bytecode(me.prog, new Uint32Array(me.memory.buffer,me.words_needed*8));
const util_imports={
clean: {
......@@ -490,6 +513,9 @@ class ABCInterpreter {
}).then(function(util){
me.util=util;
me.util.instance.exports.decode_prelinked_bytecode(me.words_needed*8);
delete me.words_needed;
const interpreter_imports={
clean: {
memory: me.memory,
......
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "abc_instructions.h"
......@@ -19,7 +20,8 @@ enum section_type {
#define _4chars2int(a,b,c,d) ((uint64_t) (a+(b<<8)+(c<<16)+(d<<24)))
#define _7chars2int(a,b,c,d,e,f,g) ((uint64_t) (a+(b<<8)+(c<<16)+(d<<24)+((uint64_t)e<<32)+((uint64_t)f<<40)+((uint64_t)g<<48)))
#define _8chars2int(a,b,c,d,e,f,g,h) ((uint64_t) (a+(b<<8)+(c<<16)+(d<<24)+((uint64_t)e<<32)+((uint64_t)f<<40)+((uint64_t)g<<48)+((uint64_t)h<<56)))
uint64_t prelinker_preamble[669] = {
uint64_t prelinker_preamble[670] = {
0, /* reserved */
/* 0 */ 0, 0, 0, 7, _7chars2int('_','A','R','R','A','Y','_'),
/* 5 */ 0, 0, 0, 8, _8chars2int('_','S','T','R','I','N','G','_'),
/* 10 */ 0, 0, 0, 4, _4chars2int('B','O','O','L'),
......@@ -70,18 +72,18 @@ uint64_t prelinker_preamble[669] = {
void prepare_preamble(void) {
for (int i=0; i<=32; i++) {
prelinker_preamble[30+i*2]=26*8+2; /* INT+2 */
prelinker_preamble[30+i*2+1]=i;
prelinker_preamble[31+i*2]=26*8+2; /* INT+2 */
prelinker_preamble[31+i*2+1]=i;
}
for (int i=0; i<256; i++) {
prelinker_preamble[146+i*2]=16*8+2; /* CHAR+2 */
prelinker_preamble[146+i*2+1]=i;
prelinker_preamble[147+i*2]=16*8+2; /* CHAR+2 */
prelinker_preamble[147+i*2+1]=i;
}
prelinker_preamble[667]=prelinker_preamble[665]=11*8+2; /* BOOL+2 */
prelinker_preamble[666]=0;
prelinker_preamble[668]=1;
prelinker_preamble[668]=prelinker_preamble[666]=11*8+2; /* BOOL+2 */
prelinker_preamble[667]=0;
prelinker_preamble[669]=1;
}
void write_section(FILE *f, enum section_type type, uint32_t len, uint64_t *data) {
......@@ -90,6 +92,34 @@ 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) {
char *ptr=safe_malloc (len*sizeof(uint64_t)*5/4); /* rough upper bound */
*dest=(uint64_t*)ptr;
*(uint32_t*)ptr=len;
ptr+=4;
while (len--) {
uint64_t val=*data++;
do {
char 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) {
uint64_t *leb_encoded_data;
uint32_t leb_encoded_len=leb128_encode (len,data,&leb_encoded_data);
write_section (f,type,leb_encoded_len,leb_encoded_data);
free (leb_encoded_data);
}
int main(int argc, char **argv) {
char *output_file_name=NULL;
FILE *input_file=NULL;
......@@ -137,9 +167,9 @@ int main(int argc, char **argv) {
struct program *program=state.program;
prepare_preamble();
write_section(output_file, ST_Preamble, sizeof(prelinker_preamble)/sizeof(uint64_t), prelinker_preamble);
write_section(output_file, ST_Code, program->code_size, program->code);
write_section(output_file, ST_Data, program->data_size, program->data);
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(output_file, ST_Start, 1, &program->symbol_table[program->start_symbol_id].offset);
fclose(output_file);
......
#pragma once
extern uint64_t prelinker_preamble[669];
extern uint64_t prelinker_preamble[670];
......@@ -255,10 +255,8 @@ int parse_program(struct parser *state, struct char_provider *cp) {
# else
state->program->data_size = elem32;
# endif
/* The prelinker writes data size between code and data segment, so reserve this space.
* TODO: better would be to use a different file format in the prelinker. */
state->program->code = safe_malloc(sizeof(BC_WORD) * (code_size+state->program->data_size+1));
state->program->data = state->program->code + code_size + 1;
state->program->code = safe_malloc(sizeof(BC_WORD) * (code_size+state->program->data_size));
state->program->data = state->program->code + code_size;
#endif
if (provide_chars(&elem32, sizeof(elem32), 1, cp) < 0)
......@@ -540,7 +538,7 @@ int parse_program(struct parser *state, struct char_provider *cp) {
# ifdef INTERPRETER
state->program->symbol_table[state->ptr].offset += (BC_WORD) state->program->data;
# elif defined(PRELINKER)
state->program->symbol_table[state->ptr].offset += ((BC_WORD)state->program->code_size+3)*8+sizeof(prelinker_preamble);
state->program->symbol_table[state->ptr].offset += ((BC_WORD)state->program->code_size)*8+sizeof(prelinker_preamble);
# endif
# ifdef LINK_CLEAN_RUNTIME
if (state->program->symbol_table[state->ptr].name[0]) {
......@@ -577,7 +575,7 @@ int parse_program(struct parser *state, struct char_provider *cp) {
# ifdef INTERPRETER
state->program->symbol_table[state->ptr].offset += (BC_WORD) state->program->code;
# elif defined(PRELINKER)
state->program->symbol_table[state->ptr].offset += 2*8+sizeof(prelinker_preamble);
state->program->symbol_table[state->ptr].offset += sizeof(prelinker_preamble);
# endif
# ifdef LINK_CLEAN_RUNTIME
if (state->program->symbol_table[state->ptr].name[0]) {
......
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