Remove waforth2c experiment

Will be superseded by `waforthc` in the future.
This commit is contained in:
Remko Tronçon 2022-07-11 21:02:07 +02:00
parent 74b4434a81
commit e0cae790dc
10 changed files with 0 additions and 628 deletions

View file

@ -1,4 +0,0 @@
waforth.gen
*.o
waforth_core.*
main

View file

@ -1,44 +0,0 @@
CFLAGS=
CPPFLAGS=-Wno-main-return-type -Wno-main -I. -Iwaforth.gen -Iwasm2c
LINKFLAGS=-g
.DEFAULT_GOAL := all
-include waforth.gen/Makefile.inc
WAFORTH_MODULE_SOURCES=$(patsubst %.wasm,%.c,$(WAFORTH_MODULES))
WAFORTH_MODULE_HEADERS=$(patsubst %.wasm,%.h,$(WAFORTH_MODULES))
WAFORTH_MODULE_OBJECTS=$(patsubst %.wasm,%.o,$(WAFORTH_MODULES))
OBJECTS=waforth_core.o main.o waforth.o wasm2c/wasm-rt-impl.o $(WAFORTH_MODULE_OBJECTS) waforth.gen/waforth_modules.o
.PHONY: all
all: main
.PHONY: example
example:
./waforth2c.js ../examples/sieve.f
$(MAKE)
./main
main: $(OBJECTS)
$(CC) $(LINKFLAGS) -o $@ $(OBJECTS)
clean:
-rm -rf $(OBJECTS) waforth_core.c waforth_core.h main $(WAFORTH_MODULE_HEADERS) $(WAFORTH_MODULE_SOURCES)
waforth.o: waforth.gen/waforth_modules.h
waforth_core.c: ../../src/waforth.wasm
wasm2c $< -o $@
waforth_core.o: waforth_core.c
$(CC) $(CPPFLAGS) $(CFLAGS) -DWASM_RT_MODULE_PREFIX=waforth_core_ -c $< -o $@
waforth.gen/waforth_module_%.c waforth.gen/waforth_module_%.h: waforth.gen/waforth_module_%.wasm
wasm2c $< -o $(subst .wasm,.c,$<)
waforth.gen/waforth_module_%.o: waforth.gen/waforth_module_%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -DWASM_RT_MODULE_PREFIX=$(subst waforth.gen/,,$(subst .o,,$@))_ -c $< -o $@
waforth.gen/waforth_modules.h: $(WAFORTH_MODULE_HEADERS)

View file

@ -1,24 +0,0 @@
# WAForth2C: Experiment to use WAForth to convert Forth to C
Uses WAForth to generate WebAssembly modules, passes them to `wasm2c`, and
compiles and loads everything together into a native binary.
## Usage
1. Create a `.f` file with a `main` word defined (e.g. `example/sieve.f`)
2. Compile
./waforth2c.js examples/sieve.f
This will generate `.wasm` files for all the defined words.
3. Build
make
This will generate `.c` files from the `.wasm` files generated in 2., and build
them using the C compiler.
4. Run
./main

View file

@ -1,6 +0,0 @@
#include "waforth.h"
int main(int argc, char** argv) {
waforth_init();
return 0;
}

View file

@ -1,67 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WASM_RT_MODULE_PREFIX waforth_core_
#include "waforth_core.h"
#undef WASM_RT_MODULE_PREFIX
#include "waforth.gen/waforth_modules.h"
void (*Z_shellZ_emitZ_vi)(u32);
u32 (*Z_shellZ_getcZ_iv)(void);
void (*Z_shellZ_loadZ_viii)(u32, u32, u32);
void (*Z_shellZ_debugZ_vi)(u32);
wasm_rt_table_t (*Z_envZ_table);
wasm_rt_memory_t (*Z_envZ_memory);
static void shellEmit(u32 c) {
printf("%c", c);
fflush(stdout);
}
static int bufferIndex;
char* buffer = "main\n";
static u32 shellGetC() {
if (bufferIndex >= strlen(buffer)) {
return -1;
}
return buffer[bufferIndex++];
}
static void shellLoad(u32 offset, u32 length, u32 index) {
printf("Loading not supported!\n");
}
static void shellDebug(u32 c) {
fprintf(stderr, "%d\n", c);
}
void wasm_rt_reallocate_table(wasm_rt_table_t* table, uint32_t elements, uint32_t max_elements) {
table->size = elements;
table->max_size = max_elements;
table->data = realloc(table->data, table->size * sizeof(wasm_rt_elem_t));
}
void waforth_init() {
waforth_core_init();
if (WAFORTH_TABLE_SIZE >= 0) {
wasm_rt_reallocate_table(waforth_core_Z_table, WAFORTH_TABLE_SIZE, waforth_core_Z_table->max_size);
}
Z_shellZ_emitZ_vi = &shellEmit;
Z_shellZ_getcZ_iv = &shellGetC;
Z_shellZ_loadZ_viii = &shellLoad;
Z_shellZ_debugZ_vi = &shellDebug;
Z_envZ_table = waforth_core_Z_table;
Z_envZ_memory = waforth_core_Z_memory;
waforth_core_Z_set_stateZ_vii(WAFORTH_LATEST, WAFORTH_HERE);
waforth_modules_init();
bufferIndex = 0;
waforth_core_Z_interpretZ_iv();
}

View file

@ -1,3 +0,0 @@
#pragma once
void waforth_init();

View file

@ -1,134 +0,0 @@
#!/usr/bin/env node
/* eslint @typescript-eslint/no-var-requires:0 */
const fs = require("fs");
const process = require("process");
if (process.argv.length < 3) {
console.log("Expected input file");
process.exit(1);
}
const input = fs.readFileSync(process.argv[2]) + "";
const coreWasm = fs.readFileSync("../../src/waforth.wasm");
let core, table, memory, memory32;
const buffer = [];
const modules = [];
let tableSize = -1;
function run(s) {
const data = new TextEncoder().encode(s);
for (let i = data.length - 1; i >= 0; --i) {
buffer.push(data[i]);
}
return core.exports.run();
}
function latest() {
run("LATEST");
const result = memory32[core.exports.tos() / 4 - 1];
run("DROP");
return result;
}
function here() {
run("HERE");
const result = memory32[core.exports.tos() / 4 - 1];
run("DROP");
return result;
}
WebAssembly.instantiate(coreWasm, {
shell: {
emit: (c) => {
process.stdout.write(String.fromCharCode(c));
},
getc: () => {
if (buffer.length === 0) {
return -1;
}
return buffer.pop();
},
debug: (c) => {
process.stderr.write(String.fromCharCode(c));
},
load: (offset, length, index) => {
let data = new Uint8Array(core.exports.memory.buffer, offset, length);
if (index >= table.length) {
table.grow(table.length);
}
tableSize = index + 1;
var module = new WebAssembly.Module(data);
modules.push(new Uint8Array(Array.from(data)));
new WebAssembly.Instance(module, {
env: { table, memory, tos: -1 },
});
},
},
}).then((instance) => {
core = instance.instance;
table = core.exports.table;
memory = core.exports.memory;
memory32 = new Int32Array(core.exports.memory.buffer, 0, 0x30000);
const memory8 = new Uint8Array(core.exports.memory.buffer, 0, 0x30000);
const dictionaryStart = latest();
// Load code
run(input);
const savedLatest = latest();
const savedHere = here();
////////////////////////////////////////////////////////////
// Generate build files
////////////////////////////////////////////////////////////
if (!fs.existsSync("waforth.gen")) {
fs.mkdirSync("waforth.gen");
}
const make = [];
const include = [
"#pragma once",
"",
"#define WAFORTH_LATEST " + savedLatest + "\n",
"#define WAFORTH_HERE " + savedHere + "\n",
"#define WAFORTH_TABLE_SIZE " + tableSize + "\n",
"void waforth_modules_init();",
"#undef WASM_RT_MODULE_PREFIX",
];
const init = [
"#include <memory.h>",
'#include "waforth_modules.h"',
"static const u8 dictionary[] = { " +
Array.from(memory8.slice(dictionaryStart, savedHere)).join(", ") +
" };",
"void waforth_modules_init() {",
"memcpy(&Z_envZ_memory->data[" +
dictionaryStart +
"], dictionary, " +
(savedHere - dictionaryStart) +
");",
];
const moduleFiles = [];
for (let i = 0; i < modules.length; ++i) {
fs.writeFileSync("waforth.gen/waforth_module_" + i + ".wasm", modules[i]);
include.push("#define WASM_RT_MODULE_PREFIX waforth_module_" + i + "_");
include.push('#include "waforth.gen/waforth_module_' + i + '.h"');
include.push("#undef WASM_RT_MODULE_PREFIX");
init.push("waforth_module_" + i + "_init();");
moduleFiles.push("waforth.gen/waforth_module_" + i + ".wasm");
}
include.push("#define WASM_RT_MODULE_PREFIX");
make.push("WAFORTH_MODULES = " + moduleFiles.join(" ") + "\n");
init.push("}");
fs.writeFileSync("waforth.gen/Makefile.inc", make.join("\n") + "\n");
fs.writeFileSync("waforth.gen/waforth_modules.h", include.join("\n") + "\n");
fs.writeFileSync("waforth.gen/waforth_modules.c", init.join("\n") + "\n");
});

View file

@ -1,122 +0,0 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "wasm-rt-impl.h"
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define PAGE_SIZE 65536
typedef struct FuncType {
wasm_rt_type_t* params;
wasm_rt_type_t* results;
uint32_t param_count;
uint32_t result_count;
} FuncType;
uint32_t wasm_rt_call_stack_depth;
uint32_t g_saved_call_stack_depth;
jmp_buf g_jmp_buf;
FuncType* g_func_types;
uint32_t g_func_type_count;
void wasm_rt_trap(wasm_rt_trap_t code) {
assert(code != WASM_RT_TRAP_NONE);
wasm_rt_call_stack_depth = g_saved_call_stack_depth;
longjmp(g_jmp_buf, code);
}
static bool func_types_are_equal(FuncType* a, FuncType* b) {
if (a->param_count != b->param_count || a->result_count != b->result_count)
return 0;
int i;
for (i = 0; i < a->param_count; ++i)
if (a->params[i] != b->params[i])
return 0;
for (i = 0; i < a->result_count; ++i)
if (a->results[i] != b->results[i])
return 0;
return 1;
}
uint32_t wasm_rt_register_func_type(uint32_t param_count,
uint32_t result_count,
...) {
FuncType func_type;
func_type.param_count = param_count;
func_type.params = malloc(param_count * sizeof(wasm_rt_type_t));
func_type.result_count = result_count;
func_type.results = malloc(result_count * sizeof(wasm_rt_type_t));
va_list args;
va_start(args, result_count);
uint32_t i;
for (i = 0; i < param_count; ++i)
func_type.params[i] = va_arg(args, wasm_rt_type_t);
for (i = 0; i < result_count; ++i)
func_type.results[i] = va_arg(args, wasm_rt_type_t);
va_end(args);
for (i = 0; i < g_func_type_count; ++i) {
if (func_types_are_equal(&g_func_types[i], &func_type)) {
free(func_type.params);
free(func_type.results);
return i + 1;
}
}
uint32_t idx = g_func_type_count++;
g_func_types = realloc(g_func_types, g_func_type_count * sizeof(FuncType));
g_func_types[idx] = func_type;
return idx + 1;
}
void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
uint32_t initial_pages,
uint32_t max_pages) {
memory->pages = initial_pages;
memory->max_pages = max_pages;
memory->size = initial_pages * PAGE_SIZE;
memory->data = calloc(memory->size, 1);
}
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
uint32_t old_pages = memory->pages;
uint32_t new_pages = memory->pages + delta;
if (new_pages < old_pages || new_pages > memory->max_pages) {
return (uint32_t)-1;
}
memory->pages = new_pages;
memory->size = new_pages * PAGE_SIZE;
memory->data = realloc(memory->data, memory->size);
memset(memory->data + old_pages * PAGE_SIZE, 0, delta * PAGE_SIZE);
return old_pages;
}
void wasm_rt_allocate_table(wasm_rt_table_t* table,
uint32_t elements,
uint32_t max_elements) {
table->size = elements;
table->max_size = max_elements;
table->data = calloc(table->size, sizeof(wasm_rt_elem_t));
}

View file

@ -1,56 +0,0 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WASM_RT_IMPL_H_
#define WASM_RT_IMPL_H_
#include <setjmp.h>
#include "wasm-rt.h"
#ifdef __cplusplus
extern "C" {
#endif
/** A setjmp buffer used for handling traps. */
extern jmp_buf g_jmp_buf;
/** Saved call stack depth that will be restored in case a trap occurs. */
extern uint32_t g_saved_call_stack_depth;
/** Convenience macro to use before calling a wasm function. On first execution
* it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will
* jump back and return the trap that occurred.
*
* ```
* wasm_rt_trap_t code = wasm_rt_impl_try();
* if (code != 0) {
* printf("A trap occurred with code: %d\n", code);
* ...
* }
*
* // Call the potentially-trapping function.
* my_wasm_func();
* ```
*/
#define wasm_rt_impl_try() \
(g_saved_call_stack_depth = wasm_rt_call_stack_depth, setjmp(g_jmp_buf))
#ifdef __cplusplus
}
#endif
#endif // WASM_RT_IMPL_H_

View file

@ -1,168 +0,0 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WASM_RT_H_
#define WASM_RT_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Maximum stack depth before trapping. This can be configured by defining
* this symbol before including wasm-rt when building the generated c files,
* for example:
*
* ```
* cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o
* ```
* */
#ifndef WASM_RT_MAX_CALL_STACK_DEPTH
#define WASM_RT_MAX_CALL_STACK_DEPTH 500
#endif
/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */
typedef enum {
WASM_RT_TRAP_NONE, /** No error. */
WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory. */
WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */
WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */
WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */
WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */
WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */
WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */
} wasm_rt_trap_t;
/** Value types. Used to define function signatures. */
typedef enum {
WASM_RT_I32,
WASM_RT_I64,
WASM_RT_F32,
WASM_RT_F64,
} wasm_rt_type_t;
/** A function type for all `anyfunc` functions in a Table. All functions are
* stored in this canonical form, but must be cast to their proper signature to
* call. */
typedef void (*wasm_rt_anyfunc_t)(void);
/** A single element of a Table. */
typedef struct {
/** The index as returned from `wasm_rt_register_func_type`. */
uint32_t func_type;
/** The function. The embedder must know the actual C signature of the
* function and cast to it before calling. */
wasm_rt_anyfunc_t func;
} wasm_rt_elem_t;
/** A Memory object. */
typedef struct {
/** The linear memory data, with a byte length of `size`. */
uint8_t* data;
/** The current and maximum page count for this Memory object. If there is no
* maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */
uint32_t pages, max_pages;
/** The current size of the linear memory, in bytes. */
uint32_t size;
} wasm_rt_memory_t;
/** A Table object. */
typedef struct {
/** The table element data, with an element count of `size`. */
wasm_rt_elem_t* data;
/** The maximum element count of this Table object. If there is no maximum,
* `max_size` is 0xffffffffu (i.e. UINT32_MAX). */
uint32_t max_size;
/** The current element count of the table. */
uint32_t size;
} wasm_rt_table_t;
/** Stop execution immediately and jump back to the call to `wasm_rt_try`.
* The result of `wasm_rt_try` will be the provided trap reason.
*
* This is typically called by the generated code, and not the embedder. */
extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));
/** Register a function type with the given signature. The returned function
* index is guaranteed to be the same for all calls with the same signature.
* The following varargs must all be of type `wasm_rt_type_t`, first the
* params` and then the `results`.
*
* ```
* // Register (func (param i32 f32) (result i64)).
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
* => returns 1
*
* // Register (func (result i64)).
* wasm_rt_register_func_type(0, 1, WASM_RT_I32);
* => returns 2
*
* // Register (func (param i32 f32) (result i64)) again.
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
* => returns 1
* ``` */
extern uint32_t wasm_rt_register_func_type(uint32_t params,
uint32_t results,
...);
/** Initialize a Memory object with an initial page size of `initial_pages` and
* a maximum page size of `max_pages`.
*
* ```
* wasm_rt_memory_t my_memory;
* // 1 initial page (65536 bytes), and a maximum of 2 pages.
* wasm_rt_allocate_memory(&my_memory, 1, 2);
* ``` */
extern void wasm_rt_allocate_memory(wasm_rt_memory_t*,
uint32_t initial_pages,
uint32_t max_pages);
/** Grow a Memory object by `pages`, and return the previous page count. If
* this new page count is greater than the maximum page count, the grow fails
* and 0xffffffffu (UINT32_MAX) is returned instead.
*
* ```
* wasm_rt_memory_t my_memory;
* ...
* // Grow memory by 10 pages.
* uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10);
* if (old_page_size == UINT32_MAX) {
* // Failed to grow memory.
* }
* ``` */
extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
/** Initialize a Table object with an element count of `elements` and a maximum
* page size of `max_elements`.
*
* ```
* wasm_rt_table_t my_table;
* // 5 elemnets and a maximum of 10 elements.
* wasm_rt_allocate_table(&my_table, 5, 10);
* ``` */
extern void wasm_rt_allocate_table(wasm_rt_table_t*,
uint32_t elements,
uint32_t max_elements);
/** Current call stack depth. */
extern uint32_t wasm_rt_call_stack_depth;
#ifdef __cplusplus
}
#endif
#endif /* WASM_RT_H_ */