Assemble kernel on the client #1
117
asm.js
117
asm.js
@@ -81,6 +81,9 @@ const State = Object.freeze({
|
|||||||
MEM_INITIAL: 9,
|
MEM_INITIAL: 9,
|
||||||
MEM_MAX: 10,
|
MEM_MAX: 10,
|
||||||
MEM_FLAGS: 11,
|
MEM_FLAGS: 11,
|
||||||
|
IMPORT_NAME: 12,
|
||||||
|
IMPORT_MOD: 13,
|
||||||
|
IMPORT_FIELD: 14
|
||||||
});
|
});
|
||||||
|
|
||||||
const Action = Object.freeze({
|
const Action = Object.freeze({
|
||||||
@@ -92,6 +95,7 @@ const Action = Object.freeze({
|
|||||||
SYMBOL: 5,
|
SYMBOL: 5,
|
||||||
LOCAL: 6,
|
LOCAL: 6,
|
||||||
MEM: 7,
|
MEM: 7,
|
||||||
|
IMPORT: 8,
|
||||||
});
|
});
|
||||||
|
|
||||||
const types = {
|
const types = {
|
||||||
@@ -126,6 +130,7 @@ class Parser {
|
|||||||
".param": State.PARAM_NAME,
|
".param": State.PARAM_NAME,
|
||||||
".local": State.LOCAL_NAME,
|
".local": State.LOCAL_NAME,
|
||||||
".mem": State.MEM_NAME,
|
".mem": State.MEM_NAME,
|
||||||
|
".import": State.IMPORT_NAME,
|
||||||
};
|
};
|
||||||
this.handlers = {
|
this.handlers = {
|
||||||
[State.TOP]: (token) => this.token_top(token),
|
[State.TOP]: (token) => this.token_top(token),
|
||||||
@@ -140,6 +145,9 @@ class Parser {
|
|||||||
[State.MEM_INIT]: (token) => this.token_mem_init(token),
|
[State.MEM_INIT]: (token) => this.token_mem_init(token),
|
||||||
[State.MEM_MAX]: (token) => this.token_mem_max(token),
|
[State.MEM_MAX]: (token) => this.token_mem_max(token),
|
||||||
[State.MEM_FLAGS]: (token) => this.token_mem_flags(token),
|
[State.MEM_FLAGS]: (token) => this.token_mem_flags(token),
|
||||||
|
[State.IMPORT_NAME]: (token) => this.token_import_name(token),
|
||||||
|
[State.IMPORT_MOD]: (token) => this.token_import_mod(token),
|
||||||
|
[State.IMPORT_FIELD]: (token) => this.token_import_field(token),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.results = [];
|
this.results = [];
|
||||||
@@ -303,6 +311,55 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token_import_name(token) {
|
||||||
|
if (token == LINE_END) {
|
||||||
|
console.error(
|
||||||
|
"ERROR: Unexpected end of line in .import: expected name");
|
||||||
|
this.state = State.TOP;
|
||||||
|
} else {
|
||||||
|
this.import = { name: token };
|
||||||
|
this.state = State.IMPORT_MOD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token_import_mod(token) {
|
||||||
|
if (token == LINE_END) {
|
||||||
|
console.error(
|
||||||
|
"ERROR: Unexpected end of line in .import: expected name");
|
||||||
|
this.import = undefined;
|
||||||
|
this.state = State.TOP;
|
||||||
|
} else if (token.string == undefined) {
|
||||||
|
console.error(
|
||||||
|
`ERROR: Unexpected token {token} in .import: expected`
|
||||||
|
+ " module string");
|
||||||
|
this.import = undefined;
|
||||||
|
this.state = State.TOP;
|
||||||
|
} else {
|
||||||
|
this.import.mod = token.string;
|
||||||
|
this.state = State.IMPORT_FIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token_import_field(token) {
|
||||||
|
if (token == LINE_END) {
|
||||||
|
console.error(
|
||||||
|
"ERROR: Unexpected end of line in .import: expected name");
|
||||||
|
this.import = undefined;
|
||||||
|
this.state = State.TOP;
|
||||||
|
} else if (token.string == undefined) {
|
||||||
|
console.error(
|
||||||
|
"ERROR: Unexpected token in .import: expected field string");
|
||||||
|
this.import = undefined;
|
||||||
|
this.state = State.TOP;
|
||||||
|
} else {
|
||||||
|
this.import.field = token.string;
|
||||||
|
const action = { type: Action.IMPORT, import: this.import };
|
||||||
|
this.import = undefined;
|
||||||
|
this.state = State.TOP;
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mem_action() {
|
mem_action() {
|
||||||
const action = {
|
const action = {
|
||||||
type: Action.MEM,
|
type: Action.MEM,
|
||||||
@@ -325,12 +382,18 @@ class Parser {
|
|||||||
|
|
||||||
const Section = Object.freeze({
|
const Section = Object.freeze({
|
||||||
TYPE: 0x01,
|
TYPE: 0x01,
|
||||||
|
IMPORT: 0x02,
|
||||||
FUNC: 0x03,
|
FUNC: 0x03,
|
||||||
MEM: 0x05,
|
MEM: 0x05,
|
||||||
EXPORT: 0x07,
|
EXPORT: 0x07,
|
||||||
CODE: 0x0a,
|
CODE: 0x0a,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Kind = Object.freeze({
|
||||||
|
FUNC: 0x00,
|
||||||
|
MEM: 0x02,
|
||||||
|
});
|
||||||
|
|
||||||
export class Assembler {
|
export class Assembler {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.encoder = new TextEncoder("utf-8");
|
this.encoder = new TextEncoder("utf-8");
|
||||||
@@ -345,11 +408,13 @@ export class Assembler {
|
|||||||
[Action.SYMBOL]: (action) => this.action_symbol(action),
|
[Action.SYMBOL]: (action) => this.action_symbol(action),
|
||||||
[Action.LOCAL]: (action) => this.action_local(action),
|
[Action.LOCAL]: (action) => this.action_local(action),
|
||||||
[Action.MEM]: (action) => this.action_mem(action),
|
[Action.MEM]: (action) => this.action_mem(action),
|
||||||
|
[Action.IMPORT]: (action) => this.action_import(action),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.exports = [];
|
this.exports = [];
|
||||||
this.funcs = {};
|
this.funcs = {};
|
||||||
this.mems = {};
|
this.mems = {};
|
||||||
|
this.imports = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
action_append(action) {
|
action_append(action) {
|
||||||
@@ -358,7 +423,7 @@ export class Assembler {
|
|||||||
|
|
||||||
action_export(action) {
|
action_export(action) {
|
||||||
const index = Object.keys(this.funcs).indexOf(action.name);
|
const index = Object.keys(this.funcs).indexOf(action.name);
|
||||||
this.exports[action.name] = { kind: 0x00, index };
|
this.exports[action.name] = { kind: Kind.FUNC, index };
|
||||||
}
|
}
|
||||||
|
|
||||||
action_func(action) {
|
action_func(action) {
|
||||||
@@ -394,6 +459,19 @@ export class Assembler {
|
|||||||
Object.assign(this.mems, action.mem);
|
Object.assign(this.mems, action.mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action_import(action) {
|
||||||
|
const mem = this.mems[action.import.name];
|
||||||
|
mem.imported = true;
|
||||||
|
this.imports.push({
|
||||||
|
mod: action.import.mod,
|
||||||
|
field: action.import.field,
|
||||||
|
kind: Kind.MEM,
|
||||||
|
flags: mem.flags,
|
||||||
|
init: mem.init,
|
||||||
|
max: mem.max,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
push(chunk) {
|
push(chunk) {
|
||||||
const text = this.decoder.decode(chunk, { stream: true });
|
const text = this.decoder.decode(chunk, { stream: true });
|
||||||
for (const action of this.parser.handle(text))
|
for (const action of this.parser.handle(text))
|
||||||
@@ -426,22 +504,35 @@ export class Assembler {
|
|||||||
return [ contents.length ].concat(...contents);
|
return [ contents.length ].concat(...contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasm_section_import() {
|
||||||
|
if (this.imports.length == 0)
|
||||||
|
return null;
|
||||||
|
const contents = this.imports.map((imp) => {
|
||||||
|
const mod_utf8 = this.encoder.encode(imp.mod);
|
||||||
|
const field_utf8 = this.encoder.encode(imp.field);
|
||||||
|
return [
|
||||||
|
mod_utf8.length,
|
||||||
|
...mod_utf8,
|
||||||
|
field_utf8.length,
|
||||||
|
...field_utf8,
|
||||||
|
imp.kind,
|
||||||
|
...this.mem_wasm(imp),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
return [ this.imports.length ].concat(...contents);
|
||||||
|
}
|
||||||
|
|
||||||
wasm_section_func() {
|
wasm_section_func() {
|
||||||
const func_count = Object.entries(this.funcs).length;
|
const func_count = Object.entries(this.funcs).length;
|
||||||
return [ func_count, ...Array(func_count).keys() ];
|
return [ func_count, ...Array(func_count).keys() ];
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm_section_mem() {
|
wasm_section_mem() {
|
||||||
const mems = Object.values(this.mems);
|
const mems = Object.values(this.mems).filter(
|
||||||
|
({imported}) => !imported);
|
||||||
if (mems.length == 0)
|
if (mems.length == 0)
|
||||||
return null;
|
return null;
|
||||||
|
const contents = mems.map((mem) => this.mem_wasm(mem));
|
||||||
const contents = mems.map(({ init, max, flags }) => {
|
|
||||||
if (flags & mem_flags.max)
|
|
||||||
return [ flags, init, max ];
|
|
||||||
else
|
|
||||||
return [ flags, init ];
|
|
||||||
});
|
|
||||||
return [ mems.length ].concat(...contents);
|
return [ mems.length ].concat(...contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +570,7 @@ export class Assembler {
|
|||||||
wasm() {
|
wasm() {
|
||||||
const template = [
|
const template = [
|
||||||
[ Section.TYPE, () => this.wasm_section_type() ],
|
[ Section.TYPE, () => this.wasm_section_type() ],
|
||||||
|
[ Section.IMPORT, () => this.wasm_section_import() ],
|
||||||
[ Section.FUNC, () => this.wasm_section_func() ],
|
[ Section.FUNC, () => this.wasm_section_func() ],
|
||||||
[ Section.MEM, () => this.wasm_section_mem() ],
|
[ Section.MEM, () => this.wasm_section_mem() ],
|
||||||
[ Section.EXPORT, () => this.wasm_section_export() ],
|
[ Section.EXPORT, () => this.wasm_section_export() ],
|
||||||
@@ -491,4 +583,11 @@ export class Assembler {
|
|||||||
|
|
||||||
return new Uint8Array(HEADER.concat(...sections));
|
return new Uint8Array(HEADER.concat(...sections));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_wasm({ flags, init, max }) {
|
||||||
|
if (flags & mem_flags.max)
|
||||||
|
return [ flags, init, max ];
|
||||||
|
else
|
||||||
|
return [ flags, init ];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user