From e365b77c0f5c0346013a1c6d61b05f730a0db0f9 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:09:30 +0100 Subject: [PATCH 01/16] makefile tweaks --- Makefile | 10 +++------- main.h | 2 ++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 1a560c1..7675b9b 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ else endif endif -.PHONY: help clean +.PHONY: help clean cleanall check install help: @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9\/_\.-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) @@ -65,10 +65,8 @@ v8/libv8_monolith.a: ## download the v8 static libary for linux/macos gzip -d v8/libv8_monolith.a.gz rm -f v8/libv8_monolith.a.gz -v8/v8_monolith.lib.zip: ## download the v8 static library for windows +v8/v8_monolith.lib: ## download the v8 static library for windows curl -L -o v8/v8_monolith.lib.zip https://github.com/just-js/v8/releases/download/${V8_VERSION}/libv8_monolith-${os}-${ARCH}.zip - -v8/v8_monolith.lib: v8/v8_monolith.lib.zip ## download the v8 static library for windows tar -C v8 -xf v8/v8_monolith.lib.zip main.o: ## compile the main.cc object file @@ -111,10 +109,8 @@ lib/inflate/em_inflate.c: lib/inflate/em_inflate.o: lib/inflate/em_inflate.h lib/inflate/em_inflate.c ## build the em_inflate object $(CC) -fPIC $(CARGS) $(OPT) -I. -I./v8 -I./v8/include -Ilib/inflate -o lib/inflate/em_inflate.o lib/inflate/em_inflate.c -inflate.o: lib/inflate/inflate.cc lib/inflate/em_inflate.h ## build the em_inflate object +inflate.a: lib/inflate/em_inflate.o ## build the inflate binding $(CXX) -fPIC $(CCARGS) $(OPT) -I. -I./v8 -I./v8/include -Ilib/inflate $(WARN) ${V8_FLAGS} -o inflate.o lib/inflate/inflate.cc - -inflate.a: inflate.o lib/inflate/em_inflate.o ## build the inflate binding ar crsT inflate.a inflate.o lib/inflate/em_inflate.o check: ## run the runtime sanity tests diff --git a/main.h b/main.h index 9e97a63..d509dcd 100644 --- a/main.h +++ b/main.h @@ -104,6 +104,8 @@ static const char* index_js = NULL; static unsigned int index_js_len = 0; static const char* main_js = _binary_main_js_start; + +//static unsigned main_js = _binary_main_js_start; static const char* v8flags = "--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation"; static unsigned int _v8flags_from_commandline = 1; static unsigned int _v8_threads = 2; From e7d9ff1428f7ffcf3b202e8956c3fc5b0c859b8a Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:16:35 +0100 Subject: [PATCH 02/16] fix bug when using index in compiled app --- lib/build.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/build.js b/lib/build.js index 42de8ab..322a650 100644 --- a/lib/build.js +++ b/lib/build.js @@ -269,6 +269,7 @@ static unsigned int index_js_len = _binary_${index.replace(rx, '_')}_end - _bina static unsigned int index_js_len = 0;`} static const char* main_js = _binary_${main_name}_start; +${main !== 'main.js' ? `static unsigned int main_js_len = ${main_name}_len;` : ''} static const char* v8flags = "${opts.v8flags}"; static unsigned int _v8flags_from_commandline = ${opts.v8flags ? 1 : 0}; static unsigned int _v8_threads = ${opts.v8_threads}; @@ -499,8 +500,7 @@ lib/**/deps globals.d.ts tsconfig.json ${app_name} -`)); - +`)) write_file(`tsconfig.json`, encoder.encode(`{ "files": ["${config.default.index}"], "compilerOptions": { @@ -521,19 +521,17 @@ ${app_name} }, "exclude": ["scratch", "v8", ".vscode", ".git", ".github"], "include": ["globals.d.ts", "lib"] -}`)); - +}`)) write_file(`README.md`, encoder.encode(` # Build \`\`\`sh -lo build runtime ${cwd}/${app_name} +lo build runtime ${app_name} \`\`\` # Run \`\`\`sh ./${app_name} \`\`\` - `)); - + `)) if (!is_file(`${app_name}.js`)) { write_file(`${app_name}.js`, encoder.encode(`console.log('hello')`)) } From 8e54a25b2ae27f9e23c6ceb33cd8ce6dac6d1d07 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:17:24 +0100 Subject: [PATCH 03/16] max heap of 1GB by default --- lib/gen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gen.js b/lib/gen.js index 0b1990a..bd430c4 100644 --- a/lib/gen.js +++ b/lib/gen.js @@ -595,7 +595,7 @@ static unsigned int _on_exit = ${opts.on_exit}; const defaultOpts = { v8_cleanup: 0, v8_threads: 2, - v8flags: '--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation', + v8flags: '--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation --max-heap-size 1024', on_exit: 0, prefix: '' } From f21524b7c3593d8148e147cd388f884dd4fbf2d5 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:18:18 +0100 Subject: [PATCH 04/16] fix html template issues --- lib/html.js | 111 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 25 deletions(-) diff --git a/lib/html.js b/lib/html.js index b4b479e..63e6a2b 100644 --- a/lib/html.js +++ b/lib/html.js @@ -1,13 +1,18 @@ -import { baseName } from 'lib/path.js' - -const { read_file } = lo.core - const rx = [ [/`/g, '`'], // replace backticks [/\$\{([^}]+)\}/g, '${$1}'], // replace literal variables - ${x} [/\n?\s+?([<{])/g, '$1'] ] +const unsafeCharsRegExp = /[<&]/g +const replaceMatch = (c) => c === "&" ? "&" : "<" +const escape = str => unsafeCharsRegExp.test(str) ? str.replace(unsafeCharsRegExp, replaceMatch) : str; + +function escapeHtml (value) { + if (value == null) return '' + return escape(value + '') +} + function sanitize (str, removeWhiteSpace = false) { if (removeWhiteSpace) { return str.trim() @@ -79,7 +84,7 @@ class Tokenizer { } class Parser { - constructor (root = '', rawStrings = true) { + constructor (root = '', rawStrings = true, escape = false) { this.source = [] this.args = [] this.command = '' @@ -88,11 +93,14 @@ class Parser { this.root = root this.rawStrings = rawStrings this.plugins = {} + this.inner = [] + this.escape = escape } start () { this.source = [] this.args = [] + this.inner = [] this.command = '' this.depth = 0 this.this = 'this' @@ -104,13 +112,21 @@ class Parser { } parse (token) { - const { source } = this + const { source, inner } = this const { type } = token if (type === 'string') { if (this.rawStrings) { - source.push(`html += String.raw\`${sanitize(token.value)}\``) + if (this.depth > 0) { + inner.push(`String.raw\`${sanitize(token.value)}\``) + } else { + source.push(`html = html + String.raw\`${sanitize(token.value)}\``) + } } else { - source.push(`html += "${sanitize(token.value, true)}"`) + if (this.depth > 0) { + inner.push(`${sanitize(token.value, true)}`) + } else { + source.push(`html = html + "${sanitize(token.value, true)}"`) + } } return } @@ -137,11 +153,14 @@ class Parser { } if (this.command === 'each') { this.depth++ + inner.length = 0 + //source.push(`let foo = ''`) if (value === 'this') { source.push(`for (const v${this.depth} of ${value}) {`) } else { source.push(`for (const v${this.depth} of ${this.this}.${value}) {`) } + inner.push(`html = html + \``) this.this = `v${this.depth}` return } @@ -167,7 +186,10 @@ class Parser { if (name[0] === '/') { const command = name.slice(1) if (command === 'each') { + inner.push(`\``) + source.push(inner.join('')) source.push('}') +// source.push('html = html + foo') this.depth-- } if (command === 'eachField') { @@ -180,17 +202,57 @@ class Parser { } if (this.this) { if (name === 'this') { - source.push(`html += ${this.this}`) + if (this.escape) { + source.push(`html += escapeHtml(${this.this})`) + } else { + source.push(`html += ${this.this}`) + } } else { const variable = name.split('.')[0] if (this.args.some(arg => arg === variable)) { - source.push(`html += ${name}`) + if (this.escape) { + if (this.depth > 0) { + inner.push(`\$\{escapeHtml(${name})\}`) + } else { + source.push(`html += escapeHtml(${name})`) + } + } else { + if (this.depth > 0) { + inner.push(`\$\{${name}\}`) + } else { + source.push(`html += ${name}`) + } + } } else { - source.push(`html += ${this.this}.${name}`) + if (this.escape) { + if (this.depth > 0) { + inner.push(`\$\{escapeHtml(${this.this}.${name})\}`) + } else { + source.push(`html += escapeHtml(${this.this}.${name})`) + } + } else { + if (this.depth > 0) { + inner.push(`\$\{${this.this}.${name}\}`) + } else { + source.push(`html += ${this.this}.${name}`) + } + } } } } else { - source.push(`html += ${name}`) + if (this.escape) { + if (this.depth > 0) { + + } else { + source.push(`html += escapeHtml(${name})`) + } + } else { + if (this.depth > 0) { + + } else { + source.push(`html += ${name}`) + } + } } } @@ -203,24 +265,23 @@ class Parser { } } -let index = 0 - function compile (template, name = 'template', root = '', opts = {}) { - const { plugins = {}, rawStrings } = opts + const { plugins = {}, rawStrings, escape = false } = opts const tokenizer = new Tokenizer() tokenizer.tokenize(template) - const parser = new Parser(root, rawStrings) + const parser = new Parser(root, rawStrings, escape) parser.plugins = plugins parser.all(tokenizer.tokens) - const call = new Function(...parser.args, parser.source.join('\n')) + let call + if (escape) { + const f = new Function('escapeHtml', `return function parse (${parser.args.join(', ')}) { + ${parser.source.join('\n')} + }`) + call = f(escapeHtml) + } else { + call = new Function(...parser.args, parser.source.join('\n')) + } return { call, tokenizer, parser, template } } -function load (fileName, opts = { rawStrings: true, compile: true, plugins: {} }) { - const template = read_file(fileName) - if (template === -1) return - if (opts.compile) return compile(template, fileName, baseName(fileName), opts).call - return template -} - -export { compile, load, Tokenizer, Parser, sanitize } +export { compile, Tokenizer, Parser, sanitize } From 5c9d74d7c00983018a6197605ef1cc018ae75eb4 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:18:39 +0100 Subject: [PATCH 05/16] add EINPROGRESS flag --- lib/net.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/net.js b/lib/net.js index 6b69d1d..75c9ba5 100644 --- a/lib/net.js +++ b/lib/net.js @@ -3,7 +3,7 @@ const { net } = lo.load('net') const { utf8EncodeIntoAtOffset } = lo // todo: use the constants from the bindings -const { AF_INET, AF_UNIX, SOCK_STREAM, SOCK_NONBLOCK } = net +const { AF_INET, AF_UNIX, SOCK_STREAM, SOCK_NONBLOCK, EINPROGRESS } = net //const SOCK_STREAM = 1 //const SOCK_NONBLOCK = 2048 const O_NONBLOCK = 2048 @@ -41,7 +41,8 @@ net.constants = { SOCKADDR_LEN, SOMAXCONN, O_CLOEXEC, SOCK_CLOEXEC, MSG_NOSIGNAL, PF_PACKET, SOCK_DGRAM, SOCK_RAW, ETH_P_ALL, ETH_P_ARP, SIOCGIFADDR, SIOCGIFHWADDR, SIOCGIFINDEX, IPPROTO_RAW, IFF_TUN, IFF_TAP, IFF_NO_PI, IFF_UP, IFF_DOWN, - SIOCSIFFLAGS, SIOCSIFADDR, SIOCSIFNETMASK, TUNSETIFF, TUNSETPERSIST, EAGAIN + SIOCSIFFLAGS, SIOCSIFADDR, SIOCSIFNETMASK, TUNSETIFF, TUNSETPERSIST, EAGAIN, + EINPROGRESS } function inet_aton(ip){ From 7978075f01c3907604b6ca0cbefe5a3c185806c5 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:19:04 +0100 Subject: [PATCH 06/16] seccomp wrapper module --- lib/seccomp.js | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/seccomp.js diff --git a/lib/seccomp.js b/lib/seccomp.js new file mode 100644 index 0000000..4559498 --- /dev/null +++ b/lib/seccomp.js @@ -0,0 +1,93 @@ +const { seccomp } = lo.load('seccomp') + +const { assert, utf8_decode, wrap, core } = lo + +const { strnlen } = core + +const MAX_STR = 1024 +const EM_X86_64 = 62 +const __AUDIT_ARCH_64BIT = 0x80000000 +const __AUDIT_ARCH_LE = 0x40000000 +const SCMP_ARCH_X86_64 = EM_X86_64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE +const SYSCALL_NAME_MAX_LEN = 128 +const u32 = new Uint32Array(2) +const seccomp_init = wrap(u32, seccomp.seccomp_init, 1) +const seccomp_syscall_resolve_num_arch = wrap(u32, seccomp.seccomp_syscall_resolve_num_arch, 2) +const { + seccomp_rule_add_exact, seccomp_load, seccomp_release, + seccomp_syscall_resolve_name +} = seccomp + +/* + * seccomp actions + */ + +/** + * Kill the process + */ +const SCMP_ACT_KILL_PROCESS = 0x80000000 +/** + * Kill the thread + */ +const SCMP_ACT_KILL_THREAD = 0x00000000 +/** + * Kill the thread, defined for backward compatibility + */ +const SCMP_ACT_KILL = SCMP_ACT_KILL_THREAD +/** + * Throw a SIGSYS signal + */ +const SCMP_ACT_TRAP = 0x00030000 +/** + * Notifies userspace + */ +const SCMP_ACT_NOTIFY = 0x7fc00000 +/** + * Return the specified error code + */ +const SCMP_ACT_ERRNO = (x) => (0x00050000 | ((x) & 0x0000ffff)) +/** + * Notify a tracing process with the specified value + */ +const SCMP_ACT_TRACE = (x) => (0x7ff00000 | ((x) & 0x0000ffff)) +/** + * Allow the syscall to be executed after the action has been logged + */ +const SCMP_ACT_LOG = 0x7ffc0000 +/** + * Allow the syscall to be executed + */ +const SCMP_ACT_ALLOW = 0x7fff0000 + +class Context { + ctx = 0 + + static getName (syscall_nr = 0) { + const ptr = assert(seccomp_syscall_resolve_num_arch(SCMP_ARCH_X86_64, syscall_nr)) + return utf8_decode(ptr, strnlen(ptr, MAX_STR)) + } + + static getNumber (syscall_name = '') { + return seccomp_syscall_resolve_name(syscall_name) + } + + init (defaultAction = SCMP_ACT_KILL_PROCESS) { + const ctx = seccomp_init(defaultAction) + assert(ctx) + this.ctx = ctx + } + + addRule (syscall_nr, perm = SCMP_ACT_ALLOW, action = SCMP_ACT_ALLOW) { + assert(seccomp_rule_add_exact(this.ctx, syscall_nr, action, 0) === 0) + } + + load () { + assert(seccomp_load(this.ctx) === 0) + } + + release () { + seccomp_release(this.ctx) + } +} + +export { Context } From e979b8abac7d987eabac47bf37c5309feb332204 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:20:20 +0100 Subject: [PATCH 07/16] nice names for adaurl api --- lib/ada/api.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/ada/api.js b/lib/ada/api.js index 67f2afe..9c48240 100644 --- a/lib/ada/api.js +++ b/lib/ada/api.js @@ -1,36 +1,40 @@ import { lib_api_typed } from 'lib/@typify/typify.js'; const api = lib_api_typed({ - ada_parse: { + parse: { parameters: ['pointer', 'u32'], pointers: ['const char*'], - result: 'pointer' + result: 'pointer', + name: 'ada_parse' }, - ada_parse_str: { + parse_str: { parameters: ['string', 'u32'], pointers: ['const char*'], result: 'pointer', name: 'ada_parse' }, - ada_can_parse: { + can_parse: { parameters: ['pointer', 'u32'], pointers: ['const char*'], - result: 'u32' + result: 'u32', + name: 'ada_can_parse' }, - ada_can_parse_str: { + can_parse_str: { parameters: ['string', 'u32'], pointers: ['const char*'], result: 'u32', name: 'ada_can_parse' }, - ada_get_components: { + get_components: { parameters: ['pointer'], result: 'pointer', - rpointer: 'const void*' + rpointer: 'const void*', + name: 'ada_get_components' }, - ada_free: { + free: { parameters: ['pointer'], - result: 'void' + result: 'void', + name: 'ada_free' } }) From 0a61d53d7675d26acf29053a65fe4b4e46210b29 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:20:46 +0100 Subject: [PATCH 08/16] asm api improvements --- lib/asm/assembler.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/asm/assembler.js b/lib/asm/assembler.js index 59e39f9..adce425 100644 --- a/lib/asm/assembler.js +++ b/lib/asm/assembler.js @@ -194,9 +194,10 @@ class Assembler { this.#instr.push(`push %${reg}`) if (idx < 8) { this.#codes.push([op_push_r64 + idx]) - return + return this } this.#codes.push([rex(0, 0, 0, 1), op_push_r64 + (idx % 8)]) + return this } // url: https://www.felixcloutier.com/x86/pop @@ -211,19 +212,22 @@ class Assembler { this.#instr.push(`pop %${reg}`) if (idx < 8) { this.#codes.push([op_pop_r64 + idx]) - return + return this } this.#codes.push([rex(0, 0, 0, 1), op_pop_r64 + (idx % 8)]) + return this } // url: https://www.felixcloutier.com/x86/add add (reg, bytes) { - return this.#add_or_sub(reg, bytes, 'add') + this.#add_or_sub(reg, bytes, 'add') + return this } // url: https://www.felixcloutier.com/x86/sub sub (reg, bytes) { - return this.#add_or_sub(reg, bytes, 'sub') + this.#add_or_sub(reg, bytes, 'sub') + return this } // url: https://www.felixcloutier.com/x86/call @@ -233,6 +237,7 @@ class Assembler { // Op/En: M // 1: ModRM:r/m (r) this.#call_or_jmp(address, reg, 'call') + return this } // url: https://www.felixcloutier.com/x86/jmp @@ -242,6 +247,7 @@ class Assembler { // Op/En: M // 1: ModRM:r/m (r) this.#call_or_jmp(address, reg, 'jmp') + return this } // url: https://www.felixcloutier.com/x86/mov @@ -255,6 +261,7 @@ class Assembler { this.#instr.push(`movabs $${address}, %${reg}`) this.#codes.push([rex(1, 0, 0, idx < 8 ? 0 : 1), op_mov_imm64 + (idx % 8), ...as_eight_bytes(address)]) + return this } movreg (src, dest) { @@ -268,6 +275,7 @@ class Assembler { this.#instr.push(`mov %${src}, %${dest}`) this.#codes.push([rex(1, src_idx > 7 ? 1 : 0, 0, dest_idx > 7 ? 1 : 0), op_mov_reg_reg, mod_rm(dest_idx % 8, src_idx % 8)]) + return this } movsrc (src, dest, off) { @@ -282,7 +290,7 @@ class Assembler { this.#instr.push(`mov (%${src}), %${dest}`) this.#codes.push([rex(1, dest_idx > 7 ? 1 : 0, 0, src_idx > 7 ? 1 : 0), op_mov_mem_reg, mod_rm(src_idx % 8, dest_idx % 8, funny_registers.includes(src) ? 1 : 0)]) - return + return this } this.#instr.push(`mov ${off}(%${src}), %${dest}`) if (src === 'rsp' || src === 'r12') { @@ -302,6 +310,7 @@ class Assembler { op_mov_mem_reg, mod_rm(src_idx % 8, dest_idx % 8, 0b10), ...as_four_bytes(off)]) } } + return this } movdest (src, dest, off) { @@ -316,7 +325,7 @@ class Assembler { this.#instr.push(`mov %${src}, (%${dest})`) this.#codes.push([rex(1, src_idx > 7 ? 1 : 0, 0, dest_idx > 7 ? 1 : 0), op_mov_reg_mem, mod_rm(dest_idx % 8, src_idx % 8, funny_registers.includes(dest) ? 1 : 0)]) - return + return this } this.#instr.push(`mov %${src}, ${off}(%${dest})`) if (dest === 'rsp' || dest === 'r12') { @@ -336,11 +345,13 @@ class Assembler { op_mov_reg_mem, mod_rm(dest_idx % 8, src_idx % 8, 0b10), ...as_four_bytes(off)]) } } + return this } ret () { this.#instr.push('ret') this.#codes.push([0xc3]) + return this } reset () { @@ -349,6 +360,10 @@ class Assembler { return this } + bytes () { + return new Uint8Array(this.#codes.flat()) + } + get src () { const { codes, instr } = this return instr.map((v, i) => [`# ${codes[i].map(v => '0x' + v.toString(16))}`, v]).flat().join('\n') + '\n' From 3b08f2775db3a5db1ecc7bf881789490d5d47522 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:24:00 +0100 Subject: [PATCH 09/16] add huge pages flags to core for linux --- lib/core/api.js | 9 ++++---- lib/core/core.cc | 54 +++++++++++++++++++++++++----------------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/lib/core/api.js b/lib/core/api.js index 03995c9..1d463cd 100644 --- a/lib/core/api.js +++ b/lib/core/api.js @@ -722,8 +722,7 @@ const constants = { RTLD_NOW: 'i32', RTLD_LAZY: 'i32', RTLD_GLOBAL: 'i32', RTLD_LOCAL: 'i32', RTLD_NODELETE: 'i32', RTLD_NOLOAD: 'i32', RTLD_DEFAULT: 'u64', RTLD_NEXT: 'u64', - PROT_READ: 'i32', PROT_WRITE: 'i32', PROT_EXEC: 'i32', - + PROT_READ: 'i32', PROT_WRITE: 'i32', PROT_EXEC: 'i32' } const structs = ['clock_t'] @@ -735,7 +734,7 @@ const includes = [ 'string.h', 'termios.h' ] -// i think this is cleanest way to do this for now. would be nice to come up +// i think this is cleanest way to do this for now. would be nice to come up // with a matrix of all syscalls for all environments and generate them automatically const mac = { constants: { @@ -750,7 +749,9 @@ const linux = { LINUX_REBOOT_CMD_RESTART: 'u32', RB_POWER_OFF: 'i32', EINTR: 'i32', - MFD_CLOEXEC: 'i32' + MFD_CLOEXEC: 'i32', + MAP_HUGETLB: 'i32', + MAP_HUGE_SHIFT: 'i32' }, includes: [ 'linux/reboot.h', diff --git a/lib/core/core.cc b/lib/core/core.cc index 4130417..76a050b 100644 --- a/lib/core/core.cc +++ b/lib/core/core.cc @@ -149,47 +149,47 @@ inline uint8_t needsunwrap (lo::FastTypes t) { } v8::CTypeInfo* CTypeFromV8 (uint8_t v8Type) { - if (v8Type == lo::FastTypes::boolean) + if (v8Type == lo::FastTypes::boolean) return new v8::CTypeInfo(v8::CTypeInfo::Type::kBool); - if (v8Type == lo::FastTypes::i8) + if (v8Type == lo::FastTypes::i8) return new v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); - if (v8Type == lo::FastTypes::i16) + if (v8Type == lo::FastTypes::i16) return new v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); - if (v8Type == lo::FastTypes::i32) + if (v8Type == lo::FastTypes::i32) return new v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); - if (v8Type == lo::FastTypes::u8) + if (v8Type == lo::FastTypes::u8) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint32); - if (v8Type == lo::FastTypes::u16) + if (v8Type == lo::FastTypes::u16) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint32); - if (v8Type == lo::FastTypes::u32) + if (v8Type == lo::FastTypes::u32) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint32); - if (v8Type == lo::FastTypes::f32) + if (v8Type == lo::FastTypes::f32) return new v8::CTypeInfo(v8::CTypeInfo::Type::kFloat32); - if (v8Type == lo::FastTypes::f64) + if (v8Type == lo::FastTypes::f64) return new v8::CTypeInfo(v8::CTypeInfo::Type::kFloat64); - if (v8Type == lo::FastTypes::i64) + if (v8Type == lo::FastTypes::i64) return new v8::CTypeInfo(v8::CTypeInfo::Type::kInt64); - if (v8Type == lo::FastTypes::u64) + if (v8Type == lo::FastTypes::u64) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint64); - if (v8Type == lo::FastTypes::iSize) + if (v8Type == lo::FastTypes::iSize) return new v8::CTypeInfo(v8::CTypeInfo::Type::kInt64); - if (v8Type == lo::FastTypes::uSize) + if (v8Type == lo::FastTypes::uSize) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint64); - if (v8Type == lo::FastTypes::pointer) + if (v8Type == lo::FastTypes::pointer) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint64); - if (v8Type == lo::FastTypes::function) + if (v8Type == lo::FastTypes::function) return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint64); - if (v8Type == lo::FastTypes::string) + if (v8Type == lo::FastTypes::string) return new v8::CTypeInfo(v8::CTypeInfo::Type::kSeqOneByteString); if (v8Type == lo::FastTypes::buffer) { - return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint8, + return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint8, v8::CTypeInfo::SequenceType::kIsTypedArray, v8::CTypeInfo::Flags::kNone); } if (v8Type == lo::FastTypes::u32array) { - return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint32, + return new v8::CTypeInfo(v8::CTypeInfo::Type::kUint32, v8::CTypeInfo::SequenceType::kIsTypedArray, v8::CTypeInfo::Flags::kNone); } - return new v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); + return new v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); } void lo_fastcall (struct fastcall* state) { @@ -244,14 +244,14 @@ void SlowCallback(const FunctionCallbackInfo &args) { case FastTypes::buffer: { Local u8 = args[i].As(); - state->args[r++] = (uint64_t)((uint8_t*)u8->Buffer()->Data() + + state->args[r++] = (uint64_t)((uint8_t*)u8->Buffer()->Data() + u8->ByteOffset()); } break; case FastTypes::u32array: { Local u32 = args[i].As(); - state->args[r++] = (uint64_t)((uint8_t*)u32->Buffer()->Data() + + state->args[r++] = (uint64_t)((uint8_t*)u32->Buffer()->Data() + u32->ByteOffset()); } break; @@ -267,7 +267,7 @@ void SlowCallback(const FunctionCallbackInfo &args) { case FastTypes::f64: { //Local u32 = args[i].As(); - //state->args[r++] = (uint64_t)((uint8_t*)u32->Buffer()->Data() + + //state->args[r++] = (uint64_t)((uint8_t*)u32->Buffer()->Data() + // u32->ByteOffset()); double src = (double)args[i].As()->Value(); double* dst = (double*)&state->args[r++]; @@ -348,11 +348,11 @@ void bind_fastcallSlow(const FunctionCallbackInfo &args) { } CFunctionInfo* info = new CFunctionInfo(*rc, fastlen, cargs); CFunction* fastCFunc = new CFunction(state->wrapper, info); - Local funcTemplate = FunctionTemplate::New(isolate, + Local funcTemplate = FunctionTemplate::New(isolate, SlowCallback, data, Local(), 0, ConstructorBehavior::kThrow, SideEffectType::kHasNoSideEffect, fastCFunc ); - Local fun = + Local fun = funcTemplate->GetFunction(context).ToLocalChecked(); args.GetReturnValue().Set(fun); } @@ -366,11 +366,11 @@ void bind_slowcallSlow(const FunctionCallbackInfo &args) { tpl->SetInternalFieldCount(2); Local data = tpl->NewInstance(context).ToLocalChecked(); data->SetAlignedPointerInInternalField(1, state); - Local funcTemplate = FunctionTemplate::New(isolate, + Local funcTemplate = FunctionTemplate::New(isolate, SlowCallback, data, Local(), 0, ConstructorBehavior::kThrow, SideEffectType::kHasNoSideEffect, 0 ); - Local fun = + Local fun = funcTemplate->GetFunction(context).ToLocalChecked(); args.GetReturnValue().Set(fun); } @@ -2588,6 +2588,8 @@ void Init(Isolate* isolate, Local target) { SET_VALUE(isolate, module, "RB_POWER_OFF", Integer::New(isolate, (int32_t)RB_POWER_OFF)); SET_VALUE(isolate, module, "EINTR", Integer::New(isolate, (int32_t)EINTR)); SET_VALUE(isolate, module, "MFD_CLOEXEC", Integer::New(isolate, (int32_t)MFD_CLOEXEC)); + SET_VALUE(isolate, module, "MAP_HUGETLB", Integer::New(isolate, (int32_t)MAP_HUGETLB)); + SET_VALUE(isolate, module, "MAP_HUGE_SHIFT", Integer::New(isolate, (int32_t)MAP_HUGE_SHIFT)); #endif #ifdef __MACH__ From de3f478390b5c3d4c5197ead9adc77ecd2e00dbc Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:25:16 +0100 Subject: [PATCH 10/16] add hescape bindings --- lib/hescape/.gitignore | 2 ++ lib/hescape/api.js | 16 ++++++++++++++++ lib/hescape/build.js | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 lib/hescape/.gitignore create mode 100644 lib/hescape/api.js create mode 100644 lib/hescape/build.js diff --git a/lib/hescape/.gitignore b/lib/hescape/.gitignore new file mode 100644 index 0000000..8c06626 --- /dev/null +++ b/lib/hescape/.gitignore @@ -0,0 +1,2 @@ +hescape.c +hescape.h diff --git a/lib/hescape/api.js b/lib/hescape/api.js new file mode 100644 index 0000000..a6102e6 --- /dev/null +++ b/lib/hescape/api.js @@ -0,0 +1,16 @@ +const api = { + hesc_escape_html: { + parameters: ['pointer', 'string', 'u32'], + pointers: ['char*'], + result: 'u32' + }, +} + +const name = 'hescape' +const constants = {} +const includes = ['hescape.h'] + +const obj = ['hescape_c.o'] + + +export { name, api, constants, includes, obj } diff --git a/lib/hescape/build.js b/lib/hescape/build.js new file mode 100644 index 0000000..d294487 --- /dev/null +++ b/lib/hescape/build.js @@ -0,0 +1,20 @@ +import { exec } from 'lib/proc.js' +import { fetch } from 'lib/curl.js' +import { isFile } from 'lib/fs.js' + +const { assert } = lo + +function build (CC = 'gcc', CXX = 'g++') { + if (isFile('hescape_c.o')) return + if (!isFile('em_inflate.h')) { + fetch('https://raw.githubusercontent.com/emmanuel-marty/em_inflate/master/lib/em_inflate.h', 'em_inflate.h') + } + if (!isFile('em_inflate.c')) { + fetch('https://raw.githubusercontent.com/emmanuel-marty/em_inflate/master/lib/em_inflate.c', 'em_inflate.c') + } + const CARGS = CC.split(' ') + assert(exec(CARGS[0], [...CARGS.slice(1), '-I.', '-c', '-o', 'hescape_c.o', '-O3', '-fPIC', '-msse4.2', 'hescape.c'])[0] === 0) + //assert(exec(CARGS[0], [...CARGS.slice(1), '-I.', '-c', '-o', 'em_inflate.o', '-O2', '-fomit-frame-pointer', 'em_inflate.c'])[0] === 0) +} + +export { build } From be09205a19884d092034a1aa5006254ae9663317 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 17 May 2024 02:25:36 +0100 Subject: [PATCH 11/16] re-generated main.h --- main.h | 1 - 1 file changed, 1 deletion(-) diff --git a/main.h b/main.h index d509dcd..be5f41d 100644 --- a/main.h +++ b/main.h @@ -105,7 +105,6 @@ static unsigned int index_js_len = 0; static const char* main_js = _binary_main_js_start; -//static unsigned main_js = _binary_main_js_start; static const char* v8flags = "--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation"; static unsigned int _v8flags_from_commandline = 1; static unsigned int _v8_threads = 2; From 04361927e7c7c79250205c3483d3127059e5e794 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Sat, 1 Jun 2024 14:21:38 +0100 Subject: [PATCH 12/16] small changes --- Makefile | 4 +- globals.d.ts | 9 +- lib/asm.js | 3 +- lib/asm/compiler.js | 3 +- lib/bench.mjs | 113 ++++++++++++----------- lib/bestlines/api.js | 6 ++ lib/build.js | 41 +++++---- lib/cfzlib/build.js | 26 +++--- lib/core/api.js | 48 +++++++++- lib/core/core.cc | 210 ++++++++++++++++++++++++++++++++++++++---- lib/ffi.js | 23 ++--- lib/fs.js | 23 ++++- lib/proc.js | 3 +- lib/pthread/api.js | 1 + lib/raylib/api.js | 33 +++++++ lib/raylib/build.js | 35 +++++++ lib/repl.js | 20 +++- lib/sqlite.js | 34 ++++--- lib/zlib/api.js | 6 +- main.js | 7 ++ runtimes/lo.config.js | 4 +- 21 files changed, 491 insertions(+), 161 deletions(-) create mode 100644 lib/raylib/api.js create mode 100644 lib/raylib/build.js diff --git a/Makefile b/Makefile index 7675b9b..2302c5a 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CARGS=-c -fno-omit-frame-pointer WARN=-Werror -Wpedantic -Wall -Wextra -Wno-unused-parameter OPT=-O3 VERSION=0.0.15-pre -V8_VERSION=12.3 +V8_VERSION=12.4 RUNTIME=lo LO_HOME=$(shell pwd) BINDINGS=core.o inflate.a curl.o @@ -15,7 +15,7 @@ ARCH=x64 os=linux TARGET=${RUNTIME} LIBS=-ldl -lcurl -lssl -lz -V8_FLAGS=-DV8_COMPRESS_POINTERS -DV8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=0 -DV8_INTL_SUPPORT=1 +V8_FLAGS=-DV8_COMPRESS_POINTERS -DV8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=0 -DV8_INTL_SUPPORT=1 -DENABLE_HUGEPAGE LIB_DIRS= ifeq ($(OS),Windows_NT) diff --git a/globals.d.ts b/globals.d.ts index cbbdd44..e84b32b 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -267,9 +267,12 @@ interface Core { prot: number, flags: number, fd: number, - offset: number, - buf: Uint32Array - ): void; + offset: number + ): number; + calloc(num: number, size: number): number; + memcpy(dest: number, src: number, size: number): number; + aligned_alloc(alignment: number, size: number): number; + memmove(dest: number, src: number, size: number): number; fork(): number; sysconf(num: number): number; times(buf: TypedArray): number; diff --git a/lib/asm.js b/lib/asm.js index 6496828..f9278d4 100644 --- a/lib/asm.js +++ b/lib/asm.js @@ -24,8 +24,7 @@ function compile (code) { const address = mmap(0, code.length, PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, u32) assert(address) - memcpy(address, code.ptr, code.length, u32) - assert(addr(u32) === address) + assert(memcpy(address, code.ptr, code.length) === address) assert(mprotect(address, code.length, PROT_EXEC | PROT_READ) === 0) return address } diff --git a/lib/asm/compiler.js b/lib/asm/compiler.js index d80a107..e848041 100644 --- a/lib/asm/compiler.js +++ b/lib/asm/compiler.js @@ -23,8 +23,7 @@ class Compiler { const address = mmap(0, code.length, PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, u32) assert(address) - memcpy(address, code.ptr, code.length, u32) - assert(addr(u32) === address) + assert(memcpy(address, code.ptr, code.length) === address) assert(mprotect(address, code.length, PROT_EXEC | PROT_READ) === 0) return address } diff --git a/lib/bench.mjs b/lib/bench.mjs index 9ca1047..ffb7650 100644 --- a/lib/bench.mjs +++ b/lib/bench.mjs @@ -41,62 +41,51 @@ function pad (v, size, precision = 0) { async function wrap_mem_usage () { if (globalThis.Deno) { - if (Deno.build.os === 'linux') { - const mem = () => Math.floor((Number((new TextDecoder()).decode(Deno.readFileSync('/proc/self/stat')).split(' ')[23]) * 4096) / (1024)) - let lastusr = 0 - let lastsys = 0 - const decoder = new TextDecoder() - const cputime = () => { - const bytes = Deno.readFileSync('/proc/self/stat') - const str = decoder.decode(bytes) - const parts = str.split(' ') - const usr = Number(parts[13]) - const sys = Number(parts[14]) - //const uptime = Number(parts[21]) - const res = [usr - lastusr, 0, sys - lastsys] - lastusr = usr - lastsys = sys - return res - } - return { mem, cputime } - } else if (Deno.build.os === 'darwin') { - const usage = Deno.memoryUsage - const mem = () => Math.floor(usage().rss / 1024) - return { mem, cputime: () => [] } + if (Deno.build.os !== 'linux') return () => 0 + const mem = () => Math.floor((Number((new TextDecoder()).decode(Deno.readFileSync('/proc/self/stat')).split(' ')[23]) * 4096) / (1024)) + let lastusr = 0 + let lastsys = 0 + const decoder = new TextDecoder() + const cputime = () => { + const bytes = Deno.readFileSync('/proc/self/stat') + const str = decoder.decode(bytes) + const parts = str.split(' ') + const usr = Number(parts[13]) + const sys = Number(parts[14]) + //const uptime = Number(parts[21]) + const res = [usr - lastusr, 0, sys - lastsys] + lastusr = usr + lastsys = sys + return res } - return { mem: () => 0, cputime: () => [] } + return { mem, cputime } } if (globalThis.Bun) { - const os = require('os').platform() - if (os === 'linux') { - const fs = require('fs') - const mem = () => Math.floor((Number((new TextDecoder()).decode(fs.readFileSync('/proc/self/stat')).split(' ')[23]) * 4096) / (1024)) - //let lastuptime = 0 - let lastusr = 0 - let lastsys = 0 - const decoder = new TextDecoder() - const cputime = () => { - const bytes = fs.readFileSync('/proc/self/stat') - const str = decoder.decode(bytes) - const parts = str.split(' ') - const usr = Number(parts[13]) - const sys = Number(parts[14]) - //const uptime = Number(parts[21]) - const res = [usr - lastusr, 0, sys - lastsys] - lastusr = usr - lastsys = sys - return res - } - return { mem, cputime } + if (require('node:os').platform() !== 'linux') return () => 0 + const fs = require('node:fs') + const mem = () => Math.floor((Number((new TextDecoder()).decode(fs.readFileSync('/proc/self/stat')).split(' ')[23]) * 4096) / (1024)) + //let lastuptime = 0 + let lastusr = 0 + let lastsys = 0 + const decoder = new TextDecoder() + const cputime = () => { + const bytes = fs.readFileSync('/proc/self/stat') + const str = decoder.decode(bytes) + const parts = str.split(' ') + const usr = Number(parts[13]) + const sys = Number(parts[14]) + //const uptime = Number(parts[21]) + const res = [usr - lastusr, 0, sys - lastsys] + lastusr = usr + lastsys = sys + return res } - const usage = process.memoryUsage - const mem = () => Math.floor(usage().rss / 1024) - return { mem, cputime: () => [] } + return { mem, cputime } } if (globalThis.process) { // node.js const os = await import('os') - if (os.platform() !== 'linux') return { mem: () => 0, cputime: () => [] } + if (os.platform() !== 'linux') return () => 0 const fs = await import('fs') const mem = () => Math.floor((Number((new TextDecoder()).decode(fs.readFileSync('/proc/self/stat')).split(' ')[23]) * 4096) / (1024)) let lastusr = 0 @@ -118,7 +107,7 @@ async function wrap_mem_usage () { } if (globalThis.lo) { const { mem, cputime } = await import('lib/proc.js') - return { mem, cputime } + return { mem: () => mem() / 1024, cputime } } } @@ -156,7 +145,7 @@ async function benchAsync (name, fn, count, after = noop) { const start = performance.now() for (let i = 0; i < count; i++) await fn() const elapsed = (performance.now() - start) - const rate = Math.floor(count / (elapsed / 1000)) + const rate = Math.floor((count / (elapsed / 1000)) * 100) / 100 const nanos = 1000000000 / rate const rss = mem() console.log(`${name.slice(0, 32).padEnd(17, ' ')} ${pad(Math.floor(elapsed), 6)} ms ${AG}rate${AD} ${pad(rate, 10)} ${formatNanos(nanos)} ${AG}rss${AD} ${rss}`) @@ -211,17 +200,16 @@ class Bench { this.#end = performance.now() const elapsed = this.#end - this.#start const rate = Math.floor(count / (elapsed / 1000)) - const nanos = Math.ceil((1000000000 / rate) * 1000) / 1000 + const nanos = Math.ceil((1000000000 / rate) * 100) / 100 const rss = mem() //if (this.#display) console.log(`${this.#name} ${pad(Math.floor(elapsed), 6)} ms ${AG}rate${AD} ${pad(rate, 10)} ${formatNanos(nanos)} ${AG}rss${AD} ${rss}`) let [ usr, , sys ] = cputime() const cpu_time = elapsed / 10 usr = Math.floor((usr / cpu_time) * 100) sys = Math.floor((sys / cpu_time) * 100) - if (this.#display) { - console.log(`${AM}${this.#name.trim().padEnd(this.#name_width, ' ')}${AD} ${AY}time${AD} ${pad(Math.floor(elapsed), 6)} ${AY}rate${AD} ${pad(rate, 12)} ${AG}ns/iter${AD} ${pad(nanos, 8, 3)} ${AG}rss${AD} ${pad(rss, 8)} ${AY}usr${AD} ${usr.toString().padStart(3, ' ')} ${AY}sys${AD} ${sys.toString().padStart(3, ' ')} ${AY}tot${AD} ${(usr + sys).toString().padStart(3, ' ')}`) - } - return { name: this.#name.trim(), count, elapsed, rate, nanos, rss, runtime } + const rate_pc = Math.ceil(rate * 100 / (usr + sys)) + if (this.#display) console.log(`${AM}${this.#name.trim().padEnd(this.#name_width, ' ')}${AD} ${AY}time${AD} ${Math.floor(elapsed)} ${AY}rate${AD} ${rate} ${AM}rate/core${AD} ${rate_pc} ${AG}ns/iter${AD} ${nanos.toFixed(2)} ${AG}rss${AD} ${rss} ${AY}usr${AD} ${usr.toString().padStart(3, ' ')} ${AY}sys${AD} ${sys.toString().padStart(3, ' ')} ${AY}tot${AD} ${(usr + sys).toString().padStart(3, ' ')}`) + return { name: this.#name.trim(), count, elapsed, rate, nanos, rss, runtime, usr, sys, rate_pc } } } @@ -233,6 +221,9 @@ if (globalThis.Deno) { runtime.version = Deno.version.deno runtime.v8 = Deno.version.v8 globalThis.readFileAsText = async fn => decoder.decode(Deno.readFileSync(fn)) + globalThis.readFileAsBytes = async fn => Deno.readFileSync(fn) + globalThis.writeFileAsText = async (fn, str) => Deno.writeFileSync(fn, encoder.encode(str)) + globalThis.writeFileAsBytes = async (fn, u8) => Deno.writeFileSync(fn, u8) } else if (globalThis.lo) { globalThis.performance = { now: () => lo.hrtime() / 1000000 } globalThis.assert = lo.assert @@ -240,13 +231,19 @@ if (globalThis.Deno) { runtime.name = 'lo' runtime.version = lo.version.lo runtime.v8 = lo.version.v8 - const { readFile } = lo.core + const { readFile, writeFile } = lo.core globalThis.readFileAsText = async fn => decoder.decode(readFile(fn)) + globalThis.readFileAsBytes = async fn => readFile(fn) + globalThis.writeFileAsText = async (fn, str) => writeFile(fn, encoder.encode(str)) + globalThis.writeFileAsBytes = async (fn, u8) => writeFile(fn, u8) } else if (globalThis.Bun) { globalThis.args = Bun.argv.slice(2) runtime.name = 'bun' runtime.version = Bun.version globalThis.readFileAsText = async fn => (await Bun.file(fn).text()) + globalThis.readFileAsBytes = async fn => (await Bun.file(fn).bytes()) + globalThis.writeFileAsText = async (fn, str) => Bun.write(fn, str) + globalThis.writeFileAsBytes = async (fn, u8) => Bun.write(fn, u8) } else if (globalThis.process) { globalThis.args = process.argv.slice(2) runtime.name = 'node' @@ -254,6 +251,9 @@ if (globalThis.Deno) { runtime.v8 = process.versions.v8 const fs = await import('fs') globalThis.readFileAsText = async fn => decoder.decode(fs.readFileSync(fn)) + globalThis.readFileAsBytes = async fn => fs.readFileSync(fn) + globalThis.writeFileAsText = async (fn, str) => fs.writeFileSync(fn, encoder.encode(str)) + globalThis.writeFileAsBytes = async (fn, u8) => fs.writeFileSync(fn, u8) } globalThis.colors = colors @@ -262,6 +262,7 @@ globalThis.arrayEquals = arrayEquals const noop = () => {} const { mem, cputime } = await wrap_mem_usage() const decoder = new TextDecoder() +const encoder = new TextEncoder() if (!globalThis.assert) { function assert (condition, message, ErrorType = Error) { diff --git a/lib/bestlines/api.js b/lib/bestlines/api.js index d524173..f26fe2b 100644 --- a/lib/bestlines/api.js +++ b/lib/bestlines/api.js @@ -6,6 +6,12 @@ const api = lib_api_typed({ pointers: ['const char*'], result: 'pointer' }, + bestline_raw: { + parameters: ['buffer', 'i32', 'i32'], + pointers: ['const char*'], + result: 'pointer', + name: 'bestlineRaw' + }, cls: { parameters: ['i32'], result: 'void', name: 'bestlineClearScreen' diff --git a/lib/build.js b/lib/build.js index 322a650..3563f5e 100644 --- a/lib/build.js +++ b/lib/build.js @@ -291,7 +291,7 @@ function check_compilers () { async function build_runtime ({ libs = lo.builtins(), bindings = lo.libraries(), embeds = [], target, link_type = LINK_TYPE, opt = OPT, - v8_opts = {}, index = '', main = 'main.js' }, verbose = false) { + v8_opts = {}, index = '', main = 'main.js', link_args = LARGS }, verbose = false) { const cwd = getcwd() if (index) embeds.push(index) if (TARGET) target = TARGET @@ -348,7 +348,7 @@ async function build_runtime ({ libs = lo.builtins(), bindings = lo.libraries(), let lib_paths = await libPaths(platform_bindings.map(n => `lib/${n}/api.js`), { prefix: PREFIX }) let bin = target if (cwd !== LO_HOME) bin = `${join(cwd, target)}` - exec2([...LINK.split(' '), ...LARGS, ...opt.split(' '), ...link_type.split(' '), ...WARN, '-o', + exec2([...LINK.split(' '), ...link_args, ...opt.split(' '), ...link_type.split(' '), ...WARN, '-o', `${bin}`, `${target}.o`, 'main.o', 'builtins.o', 'v8/libv8_monolith.a', ...static_libs, ...dynamic_libs, ...lib_paths].filter(v => v).flat(), verbose) assert(chdir(cwd) === 0) @@ -425,7 +425,6 @@ async function build (args) { write_file(config_name, encoder.encode(generate_config(config.default))) } } - console.log(config_name) const runtime_config = await import(config_name) await build_runtime(runtime_config.default, verbose) } else if (action === 'binding') { @@ -461,6 +460,7 @@ async function install (args = []) { if (!HOME) throw new Error('HOME environment variable is not set') dest_path = join(HOME, '.lo/bin') } + // we need to download the stdlib and install it in ~/.lo mkdir_all_safe(dest_path) const file_path = join(dest_path, 'lo') write_file(file_path, read_file(LO_PATH), defaultWriteFlags, S_IRWXU | S_IRWXG | S_IROTH) @@ -483,14 +483,8 @@ async function uninstall (args) { console.log('uninstall not implemented') } -async function init (args) { - const app_name = fileName(lo.getcwd()) - const config = await import('runtimes/core.config.js') - config.default.target = app_name - config.default.index = `${app_name}.js` - if (!is_file(`${app_name}.config.js`)) { - write_file(`${app_name}.config.js`, encoder.encode(generate_config(config.default))) - } +function bootstrap_app_dir (app_name, config) { + // todo - don't overwrite existing write_file('.gitignore', encoder.encode(`.lo lib/**/*.cc lib/**/*.o @@ -501,6 +495,7 @@ globals.d.ts tsconfig.json ${app_name} `)) + // todo: don't overwrite existing write_file(`tsconfig.json`, encoder.encode(`{ "files": ["${config.default.index}"], "compilerOptions": { @@ -522,6 +517,7 @@ ${app_name} "exclude": ["scratch", "v8", ".vscode", ".git", ".github"], "include": ["globals.d.ts", "lib"] }`)) + // todo: don't overwrite existing write_file(`README.md`, encoder.encode(` # Build \`\`\`sh @@ -532,14 +528,26 @@ lo build runtime ${app_name} ./${app_name} \`\`\` `)) - if (!is_file(`${app_name}.js`)) { - write_file(`${app_name}.js`, encoder.encode(`console.log('hello')`)) - } if (lo.builtins().includes('globals.d.ts')) { + // todo: don't overwrite existing write_file(`globals.d.ts`, encoder.encode(lo.builtin('globals.d.ts'))) } } +async function init (args = []) { + const app_name = args[0] || fileName(lo.getcwd()) + const config = await import('runtimes/core.config.js') + config.default.target = app_name + config.default.index = `${app_name}.js` + if (!is_file(`${app_name}.config.js`)) { + write_file(`${app_name}.config.js`, encoder.encode(generate_config(config.default))) + } +// bootstrap_app_dir(app_name, config) + if (!is_file(`${app_name}.js`)) { + write_file(`${app_name}.js`, encoder.encode(`console.log('hello')`)) + } +} + const encoder = new TextEncoder() const status = new Int32Array(2) const org = getenv('LO_ORG') || 'just-js' @@ -567,7 +575,8 @@ const v8_url_prefix = `${url_prefix}/${v8_path}` // --huge-max-old-generation-size let defaultOpts = { v8_cleanup: 0, v8_threads: 2, on_exit: 0, - v8flags: '--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation' + v8flags: '--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation', + prefix: PREFIX } // todo: clean this up let c_compiler = 'gcc' @@ -606,7 +615,7 @@ const ifdefs = { const LINK = getenv('LINK') || cc_compiler const CC = getenv('CC') || c_compiler const CXX = getenv('CXX') || cc_compiler -const CFLAGS = (getenv('CFLAGS') || `-fPIC -std=c++17 -c -DV8_COMPRESS_POINTERS -DV8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=0 -DV8_INTL_SUPPORT=1`).split(' ') +const CFLAGS = (getenv('CFLAGS') || `-fPIC -std=c++17 -c -DV8_COMPRESS_POINTERS -DV8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=0 -DV8_INTL_SUPPORT=1 -DENABLE_HUGEPAGE`).split(' ') const LARGS = (getenv('LARGS') || link_args).split(' ') const so_ext = (os === 'linux' ? 'so' : (os === 'mac' ? 'so' : 'dll')) config.os = os diff --git a/lib/cfzlib/build.js b/lib/cfzlib/build.js index fcaefdc..8cef1a7 100644 --- a/lib/cfzlib/build.js +++ b/lib/cfzlib/build.js @@ -8,20 +8,20 @@ async function build () { const { chdir, mkdir, S_IRWXU, S_IRWXG, S_IROTH, S_IXOTH, readFile } = core - if (!isDir('deps/zlib')) { - mkdir('deps', S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) - assert(chdir('deps') === 0) - if (!isFile('zlib.tar.gz')) { - console.log('fetching release') - fetch('https://codeload.github.com/cloudflare/zlib/zip/886098f3f339617b4243b286f5ed364b9989e245', - 'zlib.zip') - } - exec('unzip', ['-o', 'zlib.zip']) - const cwd = lo.getcwd() - assert(lo.core.rename(`${cwd}/zlib-886098f3f339617b4243b286f5ed364b9989e245`, `${cwd}/zlib`) === 0) - assert(chdir('../') === 0) - } if (obj.some(o => !isFile(o))) { + if (!isDir('deps/zlib')) { + mkdir('deps', S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) + assert(chdir('deps') === 0) + if (!isFile('zlib.tar.gz')) { + console.log('fetching release') + fetch('https://codeload.github.com/cloudflare/zlib/zip/886098f3f339617b4243b286f5ed364b9989e245', + 'zlib.zip') + } + exec('unzip', ['-o', 'zlib.zip']) + const cwd = lo.getcwd() + assert(lo.core.rename(`${cwd}/zlib-886098f3f339617b4243b286f5ed364b9989e245`, `${cwd}/zlib`) === 0) + assert(chdir('../') === 0) + } assert(chdir('deps/zlib') === 0) // todo: --64 fails on raspberry pi for some reason // assert(exec_env('./configure', ['--static', '--const', '--64'], [['CFLAGS', '-fPIC -mtune=native -m64 -O3']])[0] === 0) diff --git a/lib/core/api.js b/lib/core/api.js index 1d463cd..81ccc39 100644 --- a/lib/core/api.js +++ b/lib/core/api.js @@ -42,6 +42,11 @@ const api = lib_api_typed({ parameters: ['i32', 'buffer', 'i32'], result: 'i32' }, + read2: { + parameters: ['i32', 'pointer', 'i32'], + result: 'i32', + name: 'read' + }, write: { parameters: ['i32', 'buffer', 'i32'], result: 'i32' @@ -53,6 +58,10 @@ const api = lib_api_typed({ result: 'i32', name: 'write' }, + putchar: { + parameters: ['i32'], + result: 'i32' + }, close: { parameters: ['i32'], result: 'i32' @@ -79,6 +88,10 @@ const api = lib_api_typed({ result: 'i32' }, // file system operations + mknod: { + parameters: ['string', 'i32', 'i32'], + result: 'i32' + }, stat: { parameters: ['string', 'buffer'], pointers: [, 'struct stat *'], @@ -194,6 +207,10 @@ const api = lib_api_typed({ parameters: ['u32', 'u32'], result: 'pointer' }, + aligned_alloc: { + parameters: ['u32', 'u32'], + result: 'pointer' + }, free: { parameters: ['pointer'], result: 'void' @@ -380,13 +397,19 @@ const api = lib_api_typed({ result: 'u32', name: 'strnlen' }, +/* mmio_signal: { parameters: [], result: 'void' }, +*/ sync: { parameters: [], result: 'void' + }, + posix_fadvise: { + parameters: ['i32', 'u32', 'u32', 'i32'], + result: 'i32' } }) @@ -399,9 +422,10 @@ const preamble = ` #include #include -#define MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE 123 +//#define MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE 123 // used for firecracker startup time testing +/* void mmio_signal (void) { unsigned long FIRST_ADDR_PAST_32BITS = (1UL << 32); unsigned long MEM_32BIT_GAP_SIZE = (768UL << 20); @@ -419,6 +443,7 @@ void mmio_signal (void) { munmap(map_base, mapped_size); close(fd); } +*/ struct fastcall { void* wrapper; @@ -722,7 +747,9 @@ const constants = { RTLD_NOW: 'i32', RTLD_LAZY: 'i32', RTLD_GLOBAL: 'i32', RTLD_LOCAL: 'i32', RTLD_NODELETE: 'i32', RTLD_NOLOAD: 'i32', RTLD_DEFAULT: 'u64', RTLD_NEXT: 'u64', - PROT_READ: 'i32', PROT_WRITE: 'i32', PROT_EXEC: 'i32' + PROT_READ: 'i32', PROT_WRITE: 'i32', PROT_EXEC: 'i32', + POSIX_FADV_SEQUENTIAL: 'i32', POSIX_FADV_WILLNEED: 'i32', POSIX_FADV_RANDOM: 'i32', + POSIX_FADV_DONTNEED: 'i32' } const structs = ['clock_t'] @@ -738,7 +765,9 @@ const includes = [ // with a matrix of all syscalls for all environments and generate them automatically const mac = { constants: { - RTLD_FIRST: 'i32' + RTLD_FIRST: 'i32', + RTLD_SELF: 'i64', + RTLD_MAIN_ONLY: 'i64' } } @@ -751,7 +780,10 @@ const linux = { EINTR: 'i32', MFD_CLOEXEC: 'i32', MAP_HUGETLB: 'i32', - MAP_HUGE_SHIFT: 'i32' + MAP_HUGE_SHIFT: 'i32', + MAP_32BIT: 'i32', + MADV_HUGEPAGE: 'i32', + MAP_FIXED: 'i32' }, includes: [ 'linux/reboot.h', @@ -819,6 +851,14 @@ const linux = { pointers: [, 'char* const*', 'char* const*'], result: 'i32', }, + getpagesize: { + parameters: [], + result: 'i32' + }, + madvise: { + parameters: ['pointer', 'u32', 'i32'], + result: 'i32' + } }, structs: ['cpu_set_t'] } diff --git a/lib/core/core.cc b/lib/core/core.cc index 76a050b..87bedb3 100644 --- a/lib/core/core.cc +++ b/lib/core/core.cc @@ -107,9 +107,10 @@ using v8::BigInt; #include #include -#define MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE 123 +//#define MAGIC_VALUE_SIGNAL_GUEST_BOOT_COMPLETE 123 // used for firecracker startup time testing +/* void mmio_signal (void) { unsigned long FIRST_ADDR_PAST_32BITS = (1UL << 32); unsigned long MEM_32BIT_GAP_SIZE = (768UL << 20); @@ -127,6 +128,7 @@ void mmio_signal (void) { munmap(map_base, mapped_size); close(fd); } +*/ struct fastcall { void* wrapper; @@ -454,6 +456,17 @@ v8::CTypeInfo rcread = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); v8::CFunctionInfo inforead = v8::CFunctionInfo(rcread, 4, cargsread); v8::CFunction pFread = v8::CFunction((const void*)&readFast, &inforead); +int32_t read2Fast(void* p, int32_t p0, void* p1, int32_t p2); +v8::CTypeInfo cargsread2[4] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint64), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), +}; +v8::CTypeInfo rcread2 = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); +v8::CFunctionInfo inforead2 = v8::CFunctionInfo(rcread2, 4, cargsread2); +v8::CFunction pFread2 = v8::CFunction((const void*)&read2Fast, &inforead2); + int32_t writeFast(void* p, int32_t p0, struct FastApiTypedArray* const p1, int32_t p2); v8::CTypeInfo cargswrite[4] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -476,6 +489,15 @@ v8::CTypeInfo rcwrite_string = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); v8::CFunctionInfo infowrite_string = v8::CFunctionInfo(rcwrite_string, 4, cargswrite_string); v8::CFunction pFwrite_string = v8::CFunction((const void*)&write_stringFast, &infowrite_string); +int32_t putcharFast(void* p, int32_t p0); +v8::CTypeInfo cargsputchar[2] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), +}; +v8::CTypeInfo rcputchar = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); +v8::CFunctionInfo infoputchar = v8::CFunctionInfo(rcputchar, 2, cargsputchar); +v8::CFunction pFputchar = v8::CFunction((const void*)&putcharFast, &infoputchar); + int32_t closeFast(void* p, int32_t p0); v8::CTypeInfo cargsclose[2] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -539,6 +561,17 @@ v8::CTypeInfo rcftruncate = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); v8::CFunctionInfo infoftruncate = v8::CFunctionInfo(rcftruncate, 3, cargsftruncate); v8::CFunction pFftruncate = v8::CFunction((const void*)&ftruncateFast, &infoftruncate); +int32_t mknodFast(void* p, struct FastOneByteString* const p0, int32_t p1, int32_t p2); +v8::CTypeInfo cargsmknod[4] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + v8::CTypeInfo(v8::CTypeInfo::Type::kSeqOneByteString), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), +}; +v8::CTypeInfo rcmknod = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); +v8::CFunctionInfo infomknod = v8::CFunctionInfo(rcmknod, 4, cargsmknod); +v8::CFunction pFmknod = v8::CFunction((const void*)&mknodFast, &infomknod); + int32_t statFast(void* p, struct FastOneByteString* const p0, struct FastApiTypedArray* const p1); v8::CTypeInfo cargsstat[3] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -813,6 +846,17 @@ v8::CTypeInfo rccalloc = v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); v8::CFunctionInfo infocalloc = v8::CFunctionInfo(rccalloc, 4, cargscalloc); v8::CFunction pFcalloc = v8::CFunction((const void*)&callocFast, &infocalloc); +void aligned_allocFast(void* p, uint32_t p0, uint32_t p1, struct FastApiTypedArray* const p_ret); +v8::CTypeInfo cargsaligned_alloc[4] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint32), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint32), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint32, v8::CTypeInfo::SequenceType::kIsTypedArray, v8::CTypeInfo::Flags::kNone) +}; +v8::CTypeInfo rcaligned_alloc = v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); +v8::CFunctionInfo infoaligned_alloc = v8::CFunctionInfo(rcaligned_alloc, 4, cargsaligned_alloc); +v8::CFunction pFaligned_alloc = v8::CFunction((const void*)&aligned_allocFast, &infoaligned_alloc); + void freeFast(void* p, void* p0); v8::CTypeInfo cargsfree[2] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -1087,15 +1131,6 @@ v8::CTypeInfo rcstrnlen_str = v8::CTypeInfo(v8::CTypeInfo::Type::kUint32); v8::CFunctionInfo infostrnlen_str = v8::CFunctionInfo(rcstrnlen_str, 3, cargsstrnlen_str); v8::CFunction pFstrnlen_str = v8::CFunction((const void*)&strnlen_strFast, &infostrnlen_str); -void mmio_signalFast(void* p); -v8::CTypeInfo cargsmmio_signal[1] = { - v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), - -}; -v8::CTypeInfo rcmmio_signal = v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); -v8::CFunctionInfo infommio_signal = v8::CFunctionInfo(rcmmio_signal, 1, cargsmmio_signal); -v8::CFunction pFmmio_signal = v8::CFunction((const void*)&mmio_signalFast, &infommio_signal); - void syncFast(void* p); v8::CTypeInfo cargssync[1] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -1105,6 +1140,18 @@ v8::CTypeInfo rcsync = v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); v8::CFunctionInfo infosync = v8::CFunctionInfo(rcsync, 1, cargssync); v8::CFunction pFsync = v8::CFunction((const void*)&syncFast, &infosync); +int32_t posix_fadviseFast(void* p, int32_t p0, uint32_t p1, uint32_t p2, int32_t p3); +v8::CTypeInfo cargsposix_fadvise[5] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint32), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint32), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), +}; +v8::CTypeInfo rcposix_fadvise = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); +v8::CFunctionInfo infoposix_fadvise = v8::CFunctionInfo(rcposix_fadvise, 5, cargsposix_fadvise); +v8::CFunction pFposix_fadvise = v8::CFunction((const void*)&posix_fadviseFast, &infoposix_fadvise); + #ifdef __linux__ int32_t ioctlFast(void* p, int32_t p0, uint32_t p1, struct FastApiTypedArray* const p2); @@ -1237,6 +1284,26 @@ v8::CTypeInfo rcvfexecve = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); v8::CFunctionInfo infovfexecve = v8::CFunctionInfo(rcvfexecve, 4, cargsvfexecve); v8::CFunction pFvfexecve = v8::CFunction((const void*)&vfexecveFast, &infovfexecve); +int32_t getpagesizeFast(void* p); +v8::CTypeInfo cargsgetpagesize[1] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + +}; +v8::CTypeInfo rcgetpagesize = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); +v8::CFunctionInfo infogetpagesize = v8::CFunctionInfo(rcgetpagesize, 1, cargsgetpagesize); +v8::CFunction pFgetpagesize = v8::CFunction((const void*)&getpagesizeFast, &infogetpagesize); + +int32_t madviseFast(void* p, void* p0, uint32_t p1, int32_t p2); +v8::CTypeInfo cargsmadvise[4] = { + v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint64), + v8::CTypeInfo(v8::CTypeInfo::Type::kUint32), + v8::CTypeInfo(v8::CTypeInfo::Type::kInt32), +}; +v8::CTypeInfo rcmadvise = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); +v8::CFunctionInfo infomadvise = v8::CFunctionInfo(rcmadvise, 4, cargsmadvise); +v8::CFunction pFmadvise = v8::CFunction((const void*)&madviseFast, &infomadvise); + #endif #ifdef __MACH__ @@ -1302,6 +1369,21 @@ int32_t readFast(void* p, int32_t p0, struct FastApiTypedArray* const p1, int32_ int32_t v2 = p2; return read(v0, v1, v2); } +void read2Slow(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + int32_t v0 = Local::Cast(args[0])->Value(); + void* v1 = reinterpret_cast((uint64_t)Local::Cast(args[1])->Value()); + int32_t v2 = Local::Cast(args[2])->Value(); + int32_t rc = read(v0, v1, v2); + args.GetReturnValue().Set(Number::New(isolate, rc)); +} + +int32_t read2Fast(void* p, int32_t p0, void* p1, int32_t p2) { + int32_t v0 = p0; + void* v1 = reinterpret_cast(p1); + int32_t v2 = p2; + return read(v0, v1, v2); +} void writeSlow(const FunctionCallbackInfo &args) { Isolate *isolate = args.GetIsolate(); int32_t v0 = Local::Cast(args[0])->Value(); @@ -1334,6 +1416,17 @@ int32_t write_stringFast(void* p, int32_t p0, struct FastOneByteString* const p1 int32_t v2 = p1->length; return write(v0, v1->data, v2); } +void putcharSlow(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + int32_t v0 = Local::Cast(args[0])->Value(); + int32_t rc = putchar(v0); + args.GetReturnValue().Set(Number::New(isolate, rc)); +} + +int32_t putcharFast(void* p, int32_t p0) { + int32_t v0 = p0; + return putchar(v0); +} void closeSlow(const FunctionCallbackInfo &args) { Isolate *isolate = args.GetIsolate(); int32_t v0 = Local::Cast(args[0])->Value(); @@ -1422,6 +1515,21 @@ int32_t ftruncateFast(void* p, int32_t p0, uint32_t p1) { uint32_t v1 = p1; return ftruncate(v0, v1); } +void mknodSlow(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + String::Utf8Value v0(isolate, args[0]); + int32_t v1 = Local::Cast(args[1])->Value(); + int32_t v2 = Local::Cast(args[2])->Value(); + int32_t rc = mknod(*v0, v1, v2); + args.GetReturnValue().Set(Number::New(isolate, rc)); +} + +int32_t mknodFast(void* p, struct FastOneByteString* const p0, int32_t p1, int32_t p2) { + struct FastOneByteString* const v0 = p0; + int32_t v1 = p1; + int32_t v2 = p2; + return mknod(v0->data, v1, v2); +} void statSlow(const FunctionCallbackInfo &args) { Isolate *isolate = args.GetIsolate(); String::Utf8Value v0(isolate, args[0]); @@ -1796,6 +1904,21 @@ void callocFast(void* p, uint32_t p0, uint32_t p1, struct FastApiTypedArray* con void* r = calloc(v0, v1); ((void**)p_ret->data)[0] = r; +} +void aligned_allocSlow(const FunctionCallbackInfo &args) { + uint32_t v0 = Local::Cast(args[0])->Value(); + uint32_t v1 = Local::Cast(args[1])->Value(); + void* rc = aligned_alloc(v0, v1); + Local ab = args[2].As()->Buffer(); + ((void**)ab->Data())[0] = rc; +} + +void aligned_allocFast(void* p, uint32_t p0, uint32_t p1, struct FastApiTypedArray* const p_ret) { + uint32_t v0 = p0; + uint32_t v1 = p1; + void* r = aligned_alloc(v0, v1); + ((void**)p_ret->data)[0] = r; + } void freeSlow(const FunctionCallbackInfo &args) { void* v0 = reinterpret_cast((uint64_t)Local::Cast(args[0])->Value()); @@ -2218,15 +2341,6 @@ uint32_t strnlen_strFast(void* p, struct FastOneByteString* const p0) { uint32_t v1 = p0->length; return strnlen(v0->data, v1); } -void mmio_signalSlow(const FunctionCallbackInfo &args) { - - mmio_signal(); -} - -void mmio_signalFast(void* p) { - - mmio_signal(); -} void syncSlow(const FunctionCallbackInfo &args) { sync(); @@ -2236,6 +2350,23 @@ void syncFast(void* p) { sync(); } +void posix_fadviseSlow(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + int32_t v0 = Local::Cast(args[0])->Value(); + uint32_t v1 = Local::Cast(args[1])->Value(); + uint32_t v2 = Local::Cast(args[2])->Value(); + int32_t v3 = Local::Cast(args[3])->Value(); + int32_t rc = posix_fadvise(v0, v1, v2, v3); + args.GetReturnValue().Set(Number::New(isolate, rc)); +} + +int32_t posix_fadviseFast(void* p, int32_t p0, uint32_t p1, uint32_t p2, int32_t p3) { + int32_t v0 = p0; + uint32_t v1 = p1; + uint32_t v2 = p2; + int32_t v3 = p3; + return posix_fadvise(v0, v1, v2, v3); +} #ifdef __linux__ void ioctlSlow(const FunctionCallbackInfo &args) { @@ -2424,6 +2555,32 @@ int32_t vfexecveFast(void* p, int32_t p0, struct FastApiTypedArray* const p1, st char* const* v2 = reinterpret_cast(p2->data); return vfexecve(v0, v1, v2); } +void getpagesizeSlow(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + + int32_t rc = getpagesize(); + args.GetReturnValue().Set(Number::New(isolate, rc)); +} + +int32_t getpagesizeFast(void* p) { + + return getpagesize(); +} +void madviseSlow(const FunctionCallbackInfo &args) { + Isolate *isolate = args.GetIsolate(); + void* v0 = reinterpret_cast((uint64_t)Local::Cast(args[0])->Value()); + uint32_t v1 = Local::Cast(args[1])->Value(); + int32_t v2 = Local::Cast(args[2])->Value(); + int32_t rc = madvise(v0, v1, v2); + args.GetReturnValue().Set(Number::New(isolate, rc)); +} + +int32_t madviseFast(void* p, void* p0, uint32_t p1, int32_t p2) { + void* v0 = reinterpret_cast(p0); + uint32_t v1 = p1; + int32_t v2 = p2; + return madvise(v0, v1, v2); +} #endif #ifdef __MACH__ @@ -2434,14 +2591,17 @@ void Init(Isolate* isolate, Local target) { SET_FAST_METHOD(isolate, module, "dlsym", &pFdlsym, dlsymSlow); SET_FAST_METHOD(isolate, module, "dlclose", &pFdlclose, dlcloseSlow); SET_FAST_METHOD(isolate, module, "read", &pFread, readSlow); + SET_FAST_METHOD(isolate, module, "read2", &pFread2, read2Slow); SET_FAST_METHOD(isolate, module, "write", &pFwrite, writeSlow); SET_FAST_METHOD(isolate, module, "write_string", &pFwrite_string, write_stringSlow); + SET_FAST_METHOD(isolate, module, "putchar", &pFputchar, putcharSlow); SET_FAST_METHOD(isolate, module, "close", &pFclose, closeSlow); SET_FAST_METHOD(isolate, module, "pread", &pFpread, preadSlow); SET_FAST_METHOD(isolate, module, "lseek", &pFlseek, lseekSlow); SET_FAST_METHOD(isolate, module, "fstat", &pFfstat, fstatSlow); SET_FAST_METHOD(isolate, module, "fcntl", &pFfcntl, fcntlSlow); SET_FAST_METHOD(isolate, module, "ftruncate", &pFftruncate, ftruncateSlow); + SET_FAST_METHOD(isolate, module, "mknod", &pFmknod, mknodSlow); SET_FAST_METHOD(isolate, module, "stat", &pFstat, statSlow); SET_FAST_METHOD(isolate, module, "lstat", &pFlstat, lstatSlow); SET_FAST_METHOD(isolate, module, "rename", &pFrename, renameSlow); @@ -2468,6 +2628,7 @@ void Init(Isolate* isolate, Local target) { SET_FAST_METHOD(isolate, module, "munmap", &pFmunmap, munmapSlow); SET_FAST_METHOD(isolate, module, "msync", &pFmsync, msyncSlow); SET_FAST_METHOD(isolate, module, "calloc", &pFcalloc, callocSlow); + SET_FAST_METHOD(isolate, module, "aligned_alloc", &pFaligned_alloc, aligned_allocSlow); SET_FAST_METHOD(isolate, module, "free", &pFfree, freeSlow); SET_METHOD(isolate, module, "bind_fastcall", bind_fastcallSlow); SET_METHOD(isolate, module, "bind_slowcall", bind_slowcallSlow); @@ -2502,8 +2663,8 @@ void Init(Isolate* isolate, Local target) { SET_FAST_METHOD(isolate, module, "memmem", &pFmemmem, memmemSlow); SET_FAST_METHOD(isolate, module, "strnlen", &pFstrnlen, strnlenSlow); SET_FAST_METHOD(isolate, module, "strnlen_str", &pFstrnlen_str, strnlen_strSlow); - SET_FAST_METHOD(isolate, module, "mmio_signal", &pFmmio_signal, mmio_signalSlow); SET_FAST_METHOD(isolate, module, "sync", &pFsync, syncSlow); + SET_FAST_METHOD(isolate, module, "posix_fadvise", &pFposix_fadvise, posix_fadviseSlow); #ifdef __linux__ SET_FAST_METHOD(isolate, module, "ioctl", &pFioctl, ioctlSlow); @@ -2518,6 +2679,8 @@ void Init(Isolate* isolate, Local target) { SET_FAST_METHOD(isolate, module, "vfork", &pFvfork, vforkSlow); SET_FAST_METHOD(isolate, module, "vexecve", &pFvexecve, vexecveSlow); SET_FAST_METHOD(isolate, module, "vfexecve", &pFvfexecve, vfexecveSlow); + SET_FAST_METHOD(isolate, module, "getpagesize", &pFgetpagesize, getpagesizeSlow); + SET_FAST_METHOD(isolate, module, "madvise", &pFmadvise, madviseSlow); #endif #ifdef __MACH__ @@ -2580,6 +2743,10 @@ void Init(Isolate* isolate, Local target) { SET_VALUE(isolate, module, "PROT_READ", Integer::New(isolate, (int32_t)PROT_READ)); SET_VALUE(isolate, module, "PROT_WRITE", Integer::New(isolate, (int32_t)PROT_WRITE)); SET_VALUE(isolate, module, "PROT_EXEC", Integer::New(isolate, (int32_t)PROT_EXEC)); + SET_VALUE(isolate, module, "POSIX_FADV_SEQUENTIAL", Integer::New(isolate, (int32_t)POSIX_FADV_SEQUENTIAL)); + SET_VALUE(isolate, module, "POSIX_FADV_WILLNEED", Integer::New(isolate, (int32_t)POSIX_FADV_WILLNEED)); + SET_VALUE(isolate, module, "POSIX_FADV_RANDOM", Integer::New(isolate, (int32_t)POSIX_FADV_RANDOM)); + SET_VALUE(isolate, module, "POSIX_FADV_DONTNEED", Integer::New(isolate, (int32_t)POSIX_FADV_DONTNEED)); #ifdef __linux__ SET_VALUE(isolate, module, "LINUX_REBOOT_CMD_HALT", Integer::New(isolate, (uint32_t)LINUX_REBOOT_CMD_HALT)); @@ -2590,6 +2757,9 @@ void Init(Isolate* isolate, Local target) { SET_VALUE(isolate, module, "MFD_CLOEXEC", Integer::New(isolate, (int32_t)MFD_CLOEXEC)); SET_VALUE(isolate, module, "MAP_HUGETLB", Integer::New(isolate, (int32_t)MAP_HUGETLB)); SET_VALUE(isolate, module, "MAP_HUGE_SHIFT", Integer::New(isolate, (int32_t)MAP_HUGE_SHIFT)); + SET_VALUE(isolate, module, "MAP_32BIT", Integer::New(isolate, (int32_t)MAP_32BIT)); + SET_VALUE(isolate, module, "MADV_HUGEPAGE", Integer::New(isolate, (int32_t)MADV_HUGEPAGE)); + SET_VALUE(isolate, module, "MAP_FIXED", Integer::New(isolate, (int32_t)MAP_FIXED)); #endif #ifdef __MACH__ diff --git a/lib/ffi.js b/lib/ffi.js index 677c4dd..12f2fd2 100644 --- a/lib/ffi.js +++ b/lib/ffi.js @@ -1,6 +1,6 @@ import { Registers, Assembler } from 'lib/asm.js' -const { ptr, core, wrap } = lo +const { ptr, core, wrap, assert } = lo const { fastcall, bind_fastcall, bind_slowcall, dlsym } = core const { rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, r8, r9, r10, xmm0 @@ -54,10 +54,8 @@ function stack_size (result, params) { function compile_function_call (address, result, params) { asm.reset() - if (params.length > 0 || result !== Types.void) { - asm.push(rbx) - asm.mov(rdi, rbx) - } + asm.push(rbx) + asm.mov(rdi, rbx) const size = stack_size(result, params) if (size > 0) asm.sub(rsp, size) let state_off = 56 @@ -95,7 +93,7 @@ function compile_function_call (address, result, params) { } } if (size > 0) asm.add(rsp, size) - if (params.length > 0 || result !== Types.void) asm.pop(rbx) + asm.pop(rbx) asm.ret() return asm.compile() } @@ -193,22 +191,15 @@ function bind (address, res, strparams, slow = false) { return fn } -function bindall (config, handle = 0) { +function bindall (config, addr = 0) { const mod = {} for (const key of Object.keys(config)) { const binding = {} - const { constants, api, native = {} } = config[key] -/* - for (const key of Object.keys(constants)) { - console.log(key) - console.log(dlsym(handle, key)) - } + const { constants = {}, api = {}, native = {} } = config[key] Object.assign(binding, constants) -*/ - // todo: wrap here for (const key of Object.keys(api)) { const { name, result, parameters } = api[key] - binding[key] = bind(dlsym(handle, name || key), result, parameters) + binding[key] = bind(assert(dlsym(addr, name || key)), result, parameters) if (needs_unwrap(result)) { binding[key] = wrap(handle, binding[key], parameters.length) } diff --git a/lib/fs.js b/lib/fs.js index d5e3f3c..82941de 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1,6 +1,6 @@ const { assert, readMemory, utf8Decode, wrap, core } = lo const { - closedir, unlink, rmdir, open, fstat, close, access, mkdir, strnlen, + closedir, unlink, rmdir, open, fstat, close, access, mkdir, strnlen, read, F_OK, O_RDONLY, S_IFMT, S_IFDIR, S_IFREG, S_IRWXU, S_IRWXG, NAME_MAX, O_WRONLY, O_CREAT, O_TRUNC, S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH @@ -13,6 +13,7 @@ const u8 = new Uint8Array(19) const dir_view = new DataView(u8.buffer) const stat = new Uint8Array(160) const stat32 = new Uint32Array(stat.buffer) +const st = new BigUint64Array(stat.buffer) let MODE_WORD = 6 if (core.os === 'linux' && core.arch === 'arm64') { @@ -30,6 +31,20 @@ function checkMode (val, mode) { return (val & S_IFMT) === mode } +function file_size (path) { + const fd = open(path, O_RDONLY) + assert(fd > 0, `failed to open ${path}`) + assert(fstat(fd, stat) === 0) + let size = 0 + if (core.os === 'mac') { + size = Number(st[12]) + } else { + size = Number(st[6]) + } + close(fd) + return size +} + function readEntry (handle) { readMemory(u8, handle, 19) const d_ino = dir_view.getUint32(0, true) @@ -58,6 +73,8 @@ function isDir (path) { return checkMode(stat32[MODE_WORD], S_IFDIR) } +// todo: make these safe + function mkDirAll (full_path, fileMode = S_IRWXU | S_IRWXG | S_IROTH) { const subdirs = full_path.split('/').filter(dir => dir) let path = '' @@ -131,7 +148,7 @@ const rmdir_all = rmDirAll const mkdir_all_safe = mkDirAllSafe export { - mkDirAll, rmDirAll, isFile, isDir, + mkDirAll, rmDirAll, isFile, isDir, readEntry, write_flags, read_flags, write_mode, dir_flags, - is_dir, is_file, mkdir_all, rmdir_all, mkdir_all_safe + is_dir, is_file, mkdir_all, rmdir_all, mkdir_all_safe, file_size } diff --git a/lib/proc.js b/lib/proc.js index 39abdac..5bf435c 100644 --- a/lib/proc.js +++ b/lib/proc.js @@ -31,8 +31,9 @@ if (core.os === 'linux') { const buf = ptr(new Uint8Array(1024)) const decoder = new TextDecoder() - const fd = open(`/proc/self/stat`, O_RDONLY) + let fd = 0 mem = () => { + if (fd === 0) fd = open(`/proc/self/stat`, O_RDONLY) if (pread(fd, buf, 1024, 0) > 0) return findmem(decoder.decode(buf)) return 0 } diff --git a/lib/pthread/api.js b/lib/pthread/api.js index 4641c6c..db6ec04 100644 --- a/lib/pthread/api.js +++ b/lib/pthread/api.js @@ -86,5 +86,6 @@ const name = 'pthread' const includes = ['pthread.h'] const preamble = `typedef void* (*start_routine)(void*);\n` const platform = ['linux'] +//const libs = ['pthread'] // i.e. '-lpthread' flag to gnu linker export { name, api, includes, preamble, platform, constants, linux } diff --git a/lib/raylib/api.js b/lib/raylib/api.js new file mode 100644 index 0000000..d672d56 --- /dev/null +++ b/lib/raylib/api.js @@ -0,0 +1,33 @@ +const api = { + InitWindow: { parameters: ['i32', 'i32', 'string'], result: 'void' }, + SetTargetFPS: { parameters: ['i32'], result: 'void' }, + WindowShouldClose: { parameters: [], result: 'bool' }, + IsKeyPressed: { parameters: ['i32'], result: 'bool' }, + IsGestureDetected: { parameters: ['u32'], result: 'bool' }, + BeginDrawing: { parameters: [], result: 'void' }, + ClearBackground: { + parameters: ['buffer'], + casts: ['*(Color*)'], + result: 'void', + }, + DrawText: { + parameters: ['string', 'i32', 'i32', 'i32', 'buffer'], + casts: [, , , , '*(Color*)'], + result: 'void', + }, + DrawRectangle: { + parameters: ['i32', 'i32', 'i32', 'i32', 'buffer'], + casts: [, , , , '*(Color*)'], + result: 'void', + }, + EndDrawing: { parameters: [], result: 'void' }, + CloseWindow: { parameters: [], result: 'void' }, +} + +const name = 'raylib' + +const constants = {} +const obj = ['deps/raylib/lib/libraylib.a'] +const includes = ['deps/raylib/include/raylib.h'] + +export { name, api, constants, obj, includes } diff --git a/lib/raylib/build.js b/lib/raylib/build.js new file mode 100644 index 0000000..2a8788f --- /dev/null +++ b/lib/raylib/build.js @@ -0,0 +1,35 @@ +import { fetch } from 'lib/curl.js' +import { isDir, isFile } from 'lib/fs.js' +import { exec, exec_env } from 'lib/proc.js' +import { inflate } from 'lib/inflate.js' +import { untar } from 'lib/untar.js' +import { obj } from 'lib/mbedtls/api.js' + +async function build () { + const { assert, core } = lo + const { + chdir, mkdir, S_IRWXU, S_IRWXG, S_IROTH, S_IXOTH, readFile + } = core + if (obj.some(o => !isFile(o))) { + if (!isDir('deps/raylib')) { + mkdir('deps', S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) + assert(chdir('deps') === 0) + if (!isFile('raylib.tar.gz')) { + console.log('fetching release') + fetch('https://github.com/raysan5/raylib/releases/download/5.0/raylib-5.0_linux_amd64.tar.gz', + 'raylib.tar.gz') + } + const bytes = readFile('raylib.tar.gz') + const dir_name = untar(inflate(bytes)) + const cwd = lo.getcwd() + assert(lo.core.rename(`${cwd}/${dir_name}`, `${cwd}/raylib`) === 0) + assert(chdir('../') === 0) + } + assert(chdir('deps/raylib') === 0) + assert(exec_env('./configure', ['--static', '--const'], [['CFLAGS', '-fPIC -mtune=native -O3']])[0] === 0) + assert(exec('make', ['-j', '4'])[0] === 0) + assert(chdir('../../') === 0) + } +} + +export { build } diff --git a/lib/repl.js b/lib/repl.js index dd0e848..fc4a773 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -8,7 +8,7 @@ const boot_time = Math.floor((lo.hrtime() - lo.start) / 10000) / 100 const { bestlines } = lo.load('bestlines') const { colors, utf8_decode, wrap, core, module_cache, builtins, builtin } = lo -const { strnlen } = core +const { strnlen, isatty } = core const { AG, AD, AR, AY, AM } = colors @@ -16,7 +16,9 @@ const encoder = new TextEncoder() const u32 = new Uint32Array(2) const bestline = wrap(u32, bestlines.bestline, 1) +const bestline_raw = wrap(u32, bestlines.bestline_raw, 3) const { cls, add, save, load } = bestlines +const { STDIN, STDOUT, STDERR } = core const history_path = join(core.homedir, '.lo_history') @@ -99,12 +101,22 @@ function logo () { } const MAX_LINE = 65536 +function bestline_notatty (p) { + return bestline(p) +} + +function bestline_isatty (p) { + return bestline_raw(p, STDIN, STDOUT) +} + +let nextline = (isatty(STDIN) && isatty(STDOUT)) ? bestline_isatty : bestline_notatty + async function repl () { - cls(1) +// cls(1) logo() info() let line - while (line = bestline(prompt)) { + while (line = nextline(prompt)) { try { const len = strnlen(line, MAX_LINE) if (len === 0) continue @@ -141,7 +153,7 @@ async function repl () { } else if (result.constructor.name === 'Number') { console.log(result) } else if (result.constructor.name === 'String') { - console.log(`"${result}"`) + console.log(`${result}`) } else { console.log(stringify(result)) } diff --git a/lib/sqlite.js b/lib/sqlite.js index 2f62b15..950983d 100644 --- a/lib/sqlite.js +++ b/lib/sqlite.js @@ -114,7 +114,7 @@ class Statement { types = [] names = [] columns = 0 - maxRows = 65536 + maxRows = 1 * 1024 * 1024 count = 0 constructor (db) { @@ -302,19 +302,21 @@ class Statement { source.push('}') source.push(`return ${className}`) this.Row = (new Function(source.join('\n')))() - this.rows = new Array(this.maxRows).fill(0).map(v => (new this.Row())) +// this.rows = new Array(this.maxRows).fill(0).map(v => (new this.Row())) source.length = 0 source.push(` -const { types, names, cols, rows, stmt } = this +const { types, names, cols, stmt } = this +const rows = [] let rc = sqlite.step(stmt) let i = 0 while (rc === ${ROW}) { `) - if (fixed) { - source.push(' const row = rows[i]') - } else { - source.push(` const row = rows[i] = new ${className}()`) - } +// if (fixed) { +// source.push(' const row = rows[i]') +// } else { +// source.push(` const row = rows[i] = new ${className}()`) +// } + source.push(` const row = new ${className}()`) i = 0 for (const type of types) { if (type === 1) { @@ -329,23 +331,25 @@ while (rc === ${ROW}) { i++ } source.push(` + rows.push(row) rc = sqlite.step(stmt) i++ } this.count = i sqlite.reset(stmt) -return rows.slice(0, i) +return rows `) const allsrc = source.join('\n').split('\n').filter(l => l).join('\n') this.all = (new Function('sqlite', className, `return function () {\n${allsrc}\n}`))(sqlite, this.Row) source.length = 0 - source.push(`const { types, names, rows, stmt } = this + source.push(`const { types, names, stmt } = this `) - if (fixed) { - source.push('const row = rows[0]') - } else { - source.push(`const row = rows[0] = new ${className}()`) - } +// if (fixed) { +// source.push('const row = rows[0]') +// } else { +// source.push(`const row = rows[0] = new ${className}()`) +// } + source.push(`const row = new ${className}()`) source.push(`if (sqlite.step(stmt) === ${ROW}) {`) i = 0 for (const type of types) { diff --git a/lib/zlib/api.js b/lib/zlib/api.js index 6518c54..dfd33d3 100644 --- a/lib/zlib/api.js +++ b/lib/zlib/api.js @@ -2,7 +2,7 @@ import { lib_api_typed } from 'lib/@typify/typify.js'; const api = lib_api_typed({ deflate: { - parameters: ['buffer', 'u32', 'buffer', 'u32'], + parameters: ['buffer', 'u32', 'buffer', 'u32', 'u32'], pointers: ['uint8_t*', ,'uint8_t*'], result: 'u32', name: 'zlib_deflate' @@ -18,9 +18,9 @@ const includes = ['zlib.h', 'stdint.h', 'stdlib.h'] const preamble = ` #define Z_DEFAULT_MEMLEVEL 8 -uint32_t zlib_deflate (uint8_t* src, uint32_t ssize, uint8_t* dest, uint32_t dsize) { +uint32_t zlib_deflate (uint8_t* src, uint32_t ssize, uint8_t* dest, uint32_t dsize, unsigned int compression = Z_DEFAULT_COMPRESSION) { z_stream* stream = (z_stream*)calloc(1, sizeof(z_stream)); - unsigned int compression = Z_DEFAULT_COMPRESSION; +// unsigned int compression = Z_DEFAULT_COMPRESSION; int windowbits = 31; deflateInit2(stream, compression, Z_DEFLATED, windowbits, Z_DEFAULT_MEMLEVEL, Z_DEFAULT_STRATEGY); stream->next_in = (Bytef*)src; diff --git a/main.js b/main.js index ce018c5..f865b8a 100644 --- a/main.js +++ b/main.js @@ -271,6 +271,7 @@ const builtin_cache = new Map() function on_load_builtin (identifier) { if (builtin_cache.has(identifier)) return builtin_cache.get(identifier) + // todo: use the actual index.js specified for the compiled runtime if we are in a compiled runtime if (identifier === 'worker_source.js') { builtin_cache.set(identifier, workerSource) return workerSource @@ -392,6 +393,10 @@ core.homedir = LO_HOME core.dlopen = wrap(handle, core.dlopen, 2) core.dlsym = wrap(handle, core.dlsym, 2) core.mmap = wrap(handle, core.mmap, 6) +core.calloc = wrap(handle, core.calloc, 2) +core.memcpy = wrap(handle, core.memcpy, 3) +core.memmove = wrap(handle, core.memmove, 3) +core.aligned_alloc = wrap(handle, core.aligned_alloc, 2) core.isFile = is_file core.read_file = read_file core.write_file = write_file @@ -441,6 +446,7 @@ lo.utf8_encode_into_ptr = lo.utf8EncodeIntoPtr lo.utf8_encode_into_at_offset = lo.utf8EncodeIntoAtOffset lo.utf8_length = lo.utf8Length lo.wrap_memory = lo.wrapMemory +lo.latin1_decode = lo.latin1Decode @@ -481,6 +487,7 @@ async function global_main () { if (command === 'gen') { (await import('lib/gen.js')).gen(args.slice(2)) } else if (command === 'build') { + //todo: should be awaited (await import('lib/build.js')).build(args.slice(2)) } else if (command === 'install') { (await import('lib/build.js')).install(args.slice(2)) diff --git a/runtimes/lo.config.js b/runtimes/lo.config.js index 97a3b0a..8ecbd56 100644 --- a/runtimes/lo.config.js +++ b/runtimes/lo.config.js @@ -88,9 +88,11 @@ const opt = '-O3 -march=native -mtune=native' const v8_opts = { v8_cleanup: 0, v8_threads: 2, on_exit: 0, - v8flags: '--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --cppgc-young-generation' + v8flags: '--stack-trace-limit=10 --use-strict --turbo-fast-api-calls --no-freeze-flags-after-init --max-heap-size 1024' } +//let link_type = '-rdynamic' +//const link_args = ['-g'] let link_type = '-rdynamic -static-libstdc++' if (lo.core.os === 'linux') link_type += ' -static-libgcc' From 909768b0d181581da4a0b174b41364c6efca3821 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Sat, 1 Jun 2024 17:29:08 +0100 Subject: [PATCH 13/16] fix core bindings for macos --- lib/core/api.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/core/api.js b/lib/core/api.js index 81ccc39..955ac1e 100644 --- a/lib/core/api.js +++ b/lib/core/api.js @@ -407,10 +407,6 @@ const api = lib_api_typed({ parameters: [], result: 'void' }, - posix_fadvise: { - parameters: ['i32', 'u32', 'u32', 'i32'], - result: 'i32' - } }) // optional preamble of C/C++ code to embed in the generated source file before @@ -747,9 +743,7 @@ const constants = { RTLD_NOW: 'i32', RTLD_LAZY: 'i32', RTLD_GLOBAL: 'i32', RTLD_LOCAL: 'i32', RTLD_NODELETE: 'i32', RTLD_NOLOAD: 'i32', RTLD_DEFAULT: 'u64', RTLD_NEXT: 'u64', - PROT_READ: 'i32', PROT_WRITE: 'i32', PROT_EXEC: 'i32', - POSIX_FADV_SEQUENTIAL: 'i32', POSIX_FADV_WILLNEED: 'i32', POSIX_FADV_RANDOM: 'i32', - POSIX_FADV_DONTNEED: 'i32' + PROT_READ: 'i32', PROT_WRITE: 'i32', PROT_EXEC: 'i32' } const structs = ['clock_t'] @@ -783,7 +777,9 @@ const linux = { MAP_HUGE_SHIFT: 'i32', MAP_32BIT: 'i32', MADV_HUGEPAGE: 'i32', - MAP_FIXED: 'i32' + MAP_FIXED: 'i32', + POSIX_FADV_SEQUENTIAL: 'i32', POSIX_FADV_WILLNEED: 'i32', POSIX_FADV_RANDOM: 'i32', + POSIX_FADV_DONTNEED: 'i32' }, includes: [ 'linux/reboot.h', @@ -792,6 +788,10 @@ const linux = { 'sched.h' ], api: { + posix_fadvise: { + parameters: ['i32', 'u32', 'u32', 'i32'], + result: 'i32' + }, ioctl: { parameters: ['i32', 'u32', 'buffer'], result: 'i32', From ed9e96ad6276ef83f012c9385f4fae2992a9daee Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Sat, 1 Jun 2024 19:28:05 +0100 Subject: [PATCH 14/16] forgot to rebuild core.cc --- lib/core/core.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/core/core.cc b/lib/core/core.cc index 87bedb3..28faf12 100644 --- a/lib/core/core.cc +++ b/lib/core/core.cc @@ -1140,6 +1140,8 @@ v8::CTypeInfo rcsync = v8::CTypeInfo(v8::CTypeInfo::Type::kVoid); v8::CFunctionInfo infosync = v8::CFunctionInfo(rcsync, 1, cargssync); v8::CFunction pFsync = v8::CFunction((const void*)&syncFast, &infosync); +#ifdef __linux__ + int32_t posix_fadviseFast(void* p, int32_t p0, uint32_t p1, uint32_t p2, int32_t p3); v8::CTypeInfo cargsposix_fadvise[5] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -1152,8 +1154,6 @@ v8::CTypeInfo rcposix_fadvise = v8::CTypeInfo(v8::CTypeInfo::Type::kInt32); v8::CFunctionInfo infoposix_fadvise = v8::CFunctionInfo(rcposix_fadvise, 5, cargsposix_fadvise); v8::CFunction pFposix_fadvise = v8::CFunction((const void*)&posix_fadviseFast, &infoposix_fadvise); -#ifdef __linux__ - int32_t ioctlFast(void* p, int32_t p0, uint32_t p1, struct FastApiTypedArray* const p2); v8::CTypeInfo cargsioctl[4] = { v8::CTypeInfo(v8::CTypeInfo::Type::kV8Value), @@ -2350,6 +2350,8 @@ void syncFast(void* p) { sync(); } +#ifdef __linux__ + void posix_fadviseSlow(const FunctionCallbackInfo &args) { Isolate *isolate = args.GetIsolate(); int32_t v0 = Local::Cast(args[0])->Value(); @@ -2367,8 +2369,6 @@ int32_t posix_fadviseFast(void* p, int32_t p0, uint32_t p1, uint32_t p2, int32_t int32_t v3 = p3; return posix_fadvise(v0, v1, v2, v3); } -#ifdef __linux__ - void ioctlSlow(const FunctionCallbackInfo &args) { Isolate *isolate = args.GetIsolate(); int32_t v0 = Local::Cast(args[0])->Value(); @@ -2664,9 +2664,9 @@ void Init(Isolate* isolate, Local target) { SET_FAST_METHOD(isolate, module, "strnlen", &pFstrnlen, strnlenSlow); SET_FAST_METHOD(isolate, module, "strnlen_str", &pFstrnlen_str, strnlen_strSlow); SET_FAST_METHOD(isolate, module, "sync", &pFsync, syncSlow); - SET_FAST_METHOD(isolate, module, "posix_fadvise", &pFposix_fadvise, posix_fadviseSlow); #ifdef __linux__ + SET_FAST_METHOD(isolate, module, "posix_fadvise", &pFposix_fadvise, posix_fadviseSlow); SET_FAST_METHOD(isolate, module, "ioctl", &pFioctl, ioctlSlow); SET_FAST_METHOD(isolate, module, "ioctl2", &pFioctl2, ioctl2Slow); SET_FAST_METHOD(isolate, module, "ioctl3", &pFioctl3, ioctl3Slow); @@ -2743,10 +2743,6 @@ void Init(Isolate* isolate, Local target) { SET_VALUE(isolate, module, "PROT_READ", Integer::New(isolate, (int32_t)PROT_READ)); SET_VALUE(isolate, module, "PROT_WRITE", Integer::New(isolate, (int32_t)PROT_WRITE)); SET_VALUE(isolate, module, "PROT_EXEC", Integer::New(isolate, (int32_t)PROT_EXEC)); - SET_VALUE(isolate, module, "POSIX_FADV_SEQUENTIAL", Integer::New(isolate, (int32_t)POSIX_FADV_SEQUENTIAL)); - SET_VALUE(isolate, module, "POSIX_FADV_WILLNEED", Integer::New(isolate, (int32_t)POSIX_FADV_WILLNEED)); - SET_VALUE(isolate, module, "POSIX_FADV_RANDOM", Integer::New(isolate, (int32_t)POSIX_FADV_RANDOM)); - SET_VALUE(isolate, module, "POSIX_FADV_DONTNEED", Integer::New(isolate, (int32_t)POSIX_FADV_DONTNEED)); #ifdef __linux__ SET_VALUE(isolate, module, "LINUX_REBOOT_CMD_HALT", Integer::New(isolate, (uint32_t)LINUX_REBOOT_CMD_HALT)); @@ -2760,10 +2756,16 @@ void Init(Isolate* isolate, Local target) { SET_VALUE(isolate, module, "MAP_32BIT", Integer::New(isolate, (int32_t)MAP_32BIT)); SET_VALUE(isolate, module, "MADV_HUGEPAGE", Integer::New(isolate, (int32_t)MADV_HUGEPAGE)); SET_VALUE(isolate, module, "MAP_FIXED", Integer::New(isolate, (int32_t)MAP_FIXED)); + SET_VALUE(isolate, module, "POSIX_FADV_SEQUENTIAL", Integer::New(isolate, (int32_t)POSIX_FADV_SEQUENTIAL)); + SET_VALUE(isolate, module, "POSIX_FADV_WILLNEED", Integer::New(isolate, (int32_t)POSIX_FADV_WILLNEED)); + SET_VALUE(isolate, module, "POSIX_FADV_RANDOM", Integer::New(isolate, (int32_t)POSIX_FADV_RANDOM)); + SET_VALUE(isolate, module, "POSIX_FADV_DONTNEED", Integer::New(isolate, (int32_t)POSIX_FADV_DONTNEED)); #endif #ifdef __MACH__ SET_VALUE(isolate, module, "RTLD_FIRST", Integer::New(isolate, (int32_t)RTLD_FIRST)); + SET_VALUE(isolate, module, "RTLD_SELF", BigInt::New(isolate, (int64_t)RTLD_SELF)); + SET_VALUE(isolate, module, "RTLD_MAIN_ONLY", BigInt::New(isolate, (int64_t)RTLD_MAIN_ONLY)); #endif From b993a9e35ffa609686cc5f44d84b04069e6f6502 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Tue, 4 Jun 2024 23:41:04 +0100 Subject: [PATCH 15/16] tweaks --- lib/raylib/build.js | 5 ++--- lib/system/api.js | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/raylib/build.js b/lib/raylib/build.js index 2a8788f..9918803 100644 --- a/lib/raylib/build.js +++ b/lib/raylib/build.js @@ -11,7 +11,7 @@ async function build () { chdir, mkdir, S_IRWXU, S_IRWXG, S_IROTH, S_IXOTH, readFile } = core if (obj.some(o => !isFile(o))) { - if (!isDir('deps/raylib')) { + if (!isFile('deps/raylib/configure')) { mkdir('deps', S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) assert(chdir('deps') === 0) if (!isFile('raylib.tar.gz')) { @@ -21,8 +21,7 @@ async function build () { } const bytes = readFile('raylib.tar.gz') const dir_name = untar(inflate(bytes)) - const cwd = lo.getcwd() - assert(lo.core.rename(`${cwd}/${dir_name}`, `${cwd}/raylib`) === 0) + assert(lo.core.rename(dir_name, 'raylib') === 0) assert(chdir('../') === 0) } assert(chdir('deps/raylib') === 0) diff --git a/lib/system/api.js b/lib/system/api.js index e967e0f..8de31aa 100644 --- a/lib/system/api.js +++ b/lib/system/api.js @@ -125,6 +125,9 @@ const includes = [ ] const linux = { + constants: { + EFD_NONBLOCK: 'i32', EFD_CLOEXEC: 'i32', EFD_SEMAPHORE: 'i32' + }, includes: [ 'sys/eventfd.h', 'sys/timerfd.h', From 402280a733d3fdf7fc1b78b0cbc1f8c644749890 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 7 Jun 2024 22:26:27 +0100 Subject: [PATCH 16/16] bump version --- BOOK.md | 18 +++++++++--------- Makefile | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/BOOK.md b/BOOK.md index ec6809c..f20a186 100644 --- a/BOOK.md +++ b/BOOK.md @@ -16,25 +16,25 @@ gzip compressed binary from github. on linux/x64 ```shell -curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.15-pre/lo-linux-x64.gz +curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.16-pre/lo-linux-x64.gz ``` on linux/arm64 ```shell -curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.15-pre/lo-linux-arm64.gz +curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.16-pre/lo-linux-arm64.gz ``` on macos/x64 ```shell -curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.15-pre/lo-mac-x64.gz +curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.16-pre/lo-mac-x64.gz ``` on macos/arm64 (apple silicon) ```shell -curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.15-pre/lo-mac-arm64.gz +curl -L -o lo.gz https://github.com/just-js/lo/releases/download/0.0.16-pre/lo-mac-arm64.gz ``` Then, we need to decompress the downloaded file and make it executable @@ -122,7 +122,7 @@ let's check the version number of lo and the embedded JS engine it is using ```shell ./lo --version -0.0.15-pre +0.0.16-pre ``` ### evaluating JavaScript @@ -165,9 +165,9 @@ lo has a very basic repl which you can invoke as follows ⬛⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬛ ⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛⬛ - lo 0.0.15-pre v8 12.3.219.12 + lo 0.0.16-pre v8 12.4.254.18 arch x64 os linux - boot 5.67 ms rss 34078720 + boot 6.02 ms rss 34996224 > ``` @@ -181,8 +181,8 @@ we downloaded. { version: { - lo: "0.0.15-pre", - v8: "12.3.219.12" + lo: "0.0.16-pre", + v8: "12.4.254.18" }, ... } diff --git a/Makefile b/Makefile index 2302c5a..9711cd7 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CCARGS=-std=c++17 -c -fno-omit-frame-pointer -fno-rtti -fno-exceptions CARGS=-c -fno-omit-frame-pointer WARN=-Werror -Wpedantic -Wall -Wextra -Wno-unused-parameter OPT=-O3 -VERSION=0.0.15-pre +VERSION=0.0.16-pre V8_VERSION=12.4 RUNTIME=lo LO_HOME=$(shell pwd)