Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ DIST_DIR = $(shell pwd)/dist
DEV_DATA_DIR = $(shell pwd)/data
DEV_LLVM_DIR = /usr/lib/llvm18

# Default target: build for development
.PHONY: build
build: $(BUILD_DIR)/install
$(BUILD_DIR)/install/.stamp: $(BUILD_DIR)/build/.stamp meson.build meson.py $(shell find src -name '*.c' -o -name '*.h')
uv run meson.py install -C $(BUILD_DIR)/build --destdir=$(BUILD_DIR)/install
touch $@

.PHONY: rebuild
rebuild:
touch $(BUILD_DIR)/build/.stamp
$(MAKE) $(BUILD_DIR)/install/.stamp

$(BUILD_DIR)/build/.stamp:
uv run meson.py setup $(BUILD_DIR)/build --prefix=/ -Dllvm_dir=$(DEV_LLVM_DIR)
touch $@

$(BUILD_DIR)/install/.stamp: $(BUILD_DIR)/build/.stamp
uv run meson.py install -C $(BUILD_DIR)/build --destdir=$(BUILD_DIR)/install
touch $@

# Run a development PostgreSQL instance
.PHONY: run
run: $(DEV_DATA_DIR)/.stamp
Expand Down Expand Up @@ -101,4 +102,4 @@ clean:
# Delete all build artifacts, development files, and distribution files
.PHONY: distclean
distclean: clean
rm -rf $(BUILD_DIR) $(DIST_DIR) $(DEV_DATA_DIR)
rm -rf $(BUILD_DIR) $(DIST_DIR) $(DEV_DATA_DIR) subprojects/wasm-micro-runtime-WAMR-*
14 changes: 11 additions & 3 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,11 @@ postgres_pure_lib = static_library('postgres_lib',

cc = meson.get_compiler('c')
llvm_inc_flag = '-I' + (get_option('llvm_dir') / 'include')
wamr_c_flags = ['-Wno-incompatible-pointer-types', llvm_inc_flag]
wamr_c_flags = [
'-DWASM_SUPPORT_NUL_IN_STRING=1',
'-Wno-incompatible-pointer-types',
llvm_inc_flag,
]
# https://github.com/bytecodealliance/wasm-micro-runtime/issues/4640
if cc.has_argument('-fzero-init-padding-bits=unions')
wamr_c_flags += ['-fzero-init-padding-bits=unions']
Expand Down Expand Up @@ -269,7 +273,11 @@ uncommon_shared_lib = shared_library('uncommon_shared',
# Build the Rustica Engine

rustica_shared = files(
'src/rustica/env.c',
'src/rustica/bh_log_to_pg.c',
'src/rustica/datatypes.c',
'src/rustica/adt/clock.c',
'src/rustica/adt/stringbuilder.c',
'src/rustica/adt/text.c',
)
rustica_deps = [vmlib, pg.get_variable('uuid')]
rustica_cargs = wamr.get_cmake_definitions('-DWASM')
Expand Down Expand Up @@ -301,7 +309,7 @@ executable('rustica-engine',

pg_mod_args = pg.get_variable('pg_mod_args')
shared_module(
'rustica-engine',
'rustica-engine.so',
'src/rustica/extension.c',
sources: rustica_shared,
include_directories: 'src',
Expand Down
42 changes: 42 additions & 0 deletions src/rustica/adt/clock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: 2025 燕几(北京)科技有限公司
// SPDX-License-Identifier: Apache-2.0 OR MulanPSL-2.0

#include "postgres.h"

#include "rustica/datatypes.h"

static uint64_t
realtime_micros_since_unix_epoch(wasm_exec_env_t exec_env) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (uint64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
}

static wasm_externref_obj_t
monotonic_now(wasm_exec_env_t exec_env) {
obj_t mono = rst_obj_new(exec_env, OBJ_CLOCK_MONOTONIC, NULL, 0);
INSTR_TIME_SET_CURRENT(mono->body.instr_time);
return rst_externref_of_obj(exec_env, mono);
}

static uint64_t
monotonic_nanos_since(wasm_exec_env_t exec_env, wasm_obj_t ref) {
obj_t mono = wasm_externref_obj_get_obj(ref, OBJ_CLOCK_MONOTONIC);
instr_time it;
INSTR_TIME_SET_CURRENT(it);
INSTR_TIME_SUBTRACT(it, mono->body.instr_time);
return INSTR_TIME_GET_NANOSEC(it);
}

static NativeSymbol clock_natives[] = {
{ "realtime_micros_since_unix_epoch",
realtime_micros_since_unix_epoch,
"()I" },
{ "monotonic_now", monotonic_now, "()r" },
{ "monotonic_nanos_since", monotonic_nanos_since, "(r)I" },
};

void
rst_register_natives_clock() {
REGISTER_WASM_NATIVES("env", clock_natives);
}
60 changes: 50 additions & 10 deletions src/rustica/adt/stringbuilder.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include "wasm_runtime_common.h"
#include "rustica/datatypes.h"
#include "rustica/module.h"

static wasm_externref_obj_t
sb_new(wasm_exec_env_t exec_env, int32_t size_hint) {
Expand All @@ -23,21 +22,41 @@ sb_new(wasm_exec_env_t exec_env, int32_t size_hint) {
return rst_externref_of_obj(exec_env, obj);
}

static wasm_externref_obj_t
sb_read_text(wasm_exec_env_t exec_env, wasm_obj_t ref) {
Datum txt_datum = wasm_externref_obj_get_datum(ref, TEXTOID);
text *txt = DatumGetTextPP(txt_datum);
char *start = VARDATA_ANY(txt);
obj_t obj =
rst_obj_new(exec_env, OBJ_STRING_INFO, ref, sizeof(StringInfoData));
if (txt_datum != PointerGetDatum(txt))
obj->flags |= OBJ_OWNS_BODY_MEMBERS;
obj->body.sb->data = (char *)txt;
obj->body.sb->cursor = start - (char *)txt;
obj->body.sb->len = VARSIZE_ANY_EXHDR(txt) + obj->body.sb->cursor;
obj->body.sb->maxlen = 0; // read-only
return rst_externref_of_obj(exec_env, obj);
}

static inline StringInfo
sb_ensure_string_info(wasm_obj_t refobj) {
sb_ensure_string_info(wasm_obj_t refobj, bool readonly) {
obj_t obj = wasm_externref_obj_get_obj(refobj, OBJ_STRING_INFO);
if (!readonly && obj->body.sb->maxlen == 0)
ereport(ERROR, errmsg("StringInfo is read-only"));
if (readonly && obj->body.sb->maxlen != 0)
ereport(ERROR, errmsg("StringInfo is read-write"));
return obj->body.sb;
}

static int32_t
sb_mblength(wasm_exec_env_t exec_env, wasm_obj_t refobj) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
return sb->len;
}

static int32_t
sb_write_string(wasm_exec_env_t exec_env, wasm_obj_t refobj, wasm_obj_t str) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
Datum jsstr = wasm_externref_obj_get_datum(str, TEXTOID);
text *txt = DatumGetTextPP(jsstr);
appendBinaryStringInfoNT(sb, VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt));
Expand All @@ -52,7 +71,7 @@ sb_write_substring(wasm_exec_env_t exec_env,
wasm_obj_t str,
int32_t start,
int32_t len) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
Datum jsstr = wasm_externref_obj_get_datum(str, TEXTOID);
text *txt = DatumGetTextPP(jsstr);
char *data = VARDATA_ANY(txt);
Expand All @@ -69,7 +88,7 @@ sb_write_substring(wasm_exec_env_t exec_env,

static int32_t
sb_write_char(wasm_exec_env_t exec_env, wasm_obj_t refobj, int32_t ch) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
enlargeStringInfo(sb, MAX_UNICODE_EQUIVALENT_STRING);
pg_unicode_to_server(ch, (unsigned char *)sb->data + sb->len);
sb->len += (int)strlen(sb->data + sb->len);
Expand All @@ -82,7 +101,7 @@ sb_write_bytes(wasm_exec_env_t exec_env,
wasm_obj_t bytes,
int32_t start,
int32_t len) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
bytea *b = DatumGetByteaP(wasm_externref_obj_get_datum(bytes, BYTEAOID));
if (start < 0 || start + len > VARSIZE_ANY_EXHDR(b))
ereport(ERROR, errmsg("sb_write_bytes: index out of bound"));
Expand All @@ -92,26 +111,46 @@ sb_write_bytes(wasm_exec_env_t exec_env,

static int32_t
sb_write_byte(wasm_exec_env_t exec_env, wasm_obj_t refobj, int32_t byte) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
enlargeStringInfo(sb, 1);
sb->data[sb->len++] = (char)byte;
return 0;
}

static wasm_externref_obj_t
sb_to_string(wasm_exec_env_t exec_env, wasm_obj_t refobj) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
return cstring_into_varatt_obj(exec_env, sb->data, sb->len, TEXTOID);
}

static wasm_externref_obj_t
sb_to_bytes(wasm_exec_env_t exec_env, wasm_obj_t refobj) {
StringInfo sb = sb_ensure_string_info(refobj);
StringInfo sb = sb_ensure_string_info(refobj, false);
return cstring_into_varatt_obj(exec_env, sb->data, sb->len, BYTEAOID);
}

static int32_t
sb_read_char(wasm_exec_env_t exec_env, wasm_obj_t refobj) {
int ch;
pg_wchar rv[2] = { '?', 0 };
StringInfo sb = sb_ensure_string_info(refobj, true);
if (sb->cursor >= sb->len)
return -1; // EOF
ch = pg_mblen(sb->data + sb->cursor);
if (ch > 0 && sb->cursor + ch <= sb->len) {
pg_mb2wchar_with_len(sb->data + sb->cursor, rv, ch);
sb->cursor += ch;
}
else {
// Invalid UTF-8 sequence, skip one byte
sb->cursor += 1;
}
return (int32_t)rv[0];
}

static NativeSymbol sb_symbols[] = {
{ "sb_new", sb_new, "(i)r" },
{ "si_read_text", sb_read_text, "(r)r" },
{ "sb_mblength", sb_mblength, "(r)i" },
{ "sb_write_string", sb_write_string, "(rr)i" },
{ "sb_write_substring", sb_write_substring, "(rrii)i" },
Expand All @@ -120,6 +159,7 @@ static NativeSymbol sb_symbols[] = {
{ "sb_write_byte", sb_write_byte, "(ri)i" },
{ "sb_to_string", sb_to_string, "(r)r" },
{ "sb_to_bytes", sb_to_bytes, "(r)r" },
{ "si_read_char", sb_read_char, "(r)i" },
};

void
Expand Down
Loading