MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add string_decoder module

+344 -48
+8
include/modules/string_decoder.h
··· 1 + #ifndef STRING_DECODER_H 2 + #define STRING_DECODER_H 3 + 4 + #include "types.h" 5 + 6 + ant_value_t string_decoder_library(ant_t *js); 7 + 8 + #endif
+2
src/main.c
··· 80 80 #include "modules/abort.h" 81 81 #include "modules/globals.h" 82 82 #include "modules/wasm.h" 83 + #include "modules/string_decoder.h" 83 84 #include "modules/structured-clone.h" 84 85 #include "modules/v8.h" 85 86 #include "modules/worker_threads.h" ··· 650 651 ant_standard_library("async_hooks", async_hooks_library); 651 652 ant_standard_library("v8", v8_library); 652 653 ant_standard_library("zlib", zlib_library); 654 + ant_standard_library("string_decoder", string_decoder_library); 653 655 654 656 ant_standard_library("fs/promises", fs_promises_library); 655 657 ant_standard_library("timers/promises", timers_promises_library);
+4 -1
src/modules/readline.c
··· 536 536 } else if (process_has_event_listeners("SIGINT")) { 537 537 ant_value_t sig_arg = js_mkstr(js, "SIGINT", 6); 538 538 emit_process_event("SIGINT", &sig_arg, 1); 539 - } else raise(SIGINT); 539 + } else { 540 + uv_tty_reset_mode(); 541 + raise(SIGINT); 542 + } 540 543 } else if (c == 4) { 541 544 if (iface->line_len == 0) { 542 545 emit_event(js, iface, "close", NULL, 0);
+254
src/modules/string_decoder.c
··· 1 + #include <stdlib.h> 2 + #include <string.h> 3 + #include <stdint.h> 4 + #include <stdbool.h> 5 + 6 + #include "ant.h" 7 + #include "base64.h" 8 + #include "errors.h" 9 + #include "internal.h" 10 + #include "descriptors.h" 11 + 12 + #include "modules/buffer.h" 13 + #include "modules/symbol.h" 14 + #include "modules/textcodec.h" 15 + #include "modules/string_decoder.h" 16 + 17 + #define SD_ENC_UTF8 0 18 + #define SD_ENC_UTF16LE 1 19 + #define SD_ENC_UTF16BE 2 20 + #define SD_ENC_LATIN1 3 21 + #define SD_ENC_HEX 4 22 + #define SD_ENC_BASE64 5 23 + 24 + typedef struct { 25 + int encoding; 26 + td_state_t *td; 27 + uint8_t pending[2]; 28 + int pending_len; 29 + } sd_state_t; 30 + 31 + static ant_value_t g_string_decoder_proto = 0; 32 + 33 + static sd_state_t *sd_get_state(ant_value_t obj) { 34 + ant_value_t s = js_get_slot(obj, SLOT_DATA); 35 + if (vtype(s) != T_NUM) return NULL; 36 + return (sd_state_t *)(uintptr_t)(size_t)js_getnum(s); 37 + } 38 + 39 + static void sd_finalize(ant_t *js, ant_object_t *obj) { 40 + if (!obj->extra_slots) return; 41 + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 42 + for (uint8_t i = 0; i < obj->extra_count; i++) { 43 + if (entries[i].slot == SLOT_DATA && vtype(entries[i].value) == T_NUM) { 44 + sd_state_t *st = (sd_state_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 45 + if (st) { free(st->td); free(st); } 46 + return; 47 + }} 48 + } 49 + 50 + static int sd_parse_encoding(const char *s, size_t len) { 51 + static const struct { const char *label; uint8_t llen; int enc; } map[] = { 52 + {"utf8", 4, SD_ENC_UTF8}, 53 + {"utf-8", 5, SD_ENC_UTF8}, 54 + {"utf16le", 7, SD_ENC_UTF16LE}, 55 + {"utf-16le", 8, SD_ENC_UTF16LE}, 56 + {"ucs2", 4, SD_ENC_UTF16LE}, 57 + {"ucs-2", 5, SD_ENC_UTF16LE}, 58 + {"latin1", 6, SD_ENC_LATIN1}, 59 + {"binary", 6, SD_ENC_LATIN1}, 60 + {"ascii", 5, SD_ENC_LATIN1}, 61 + {"hex", 3, SD_ENC_HEX}, 62 + {"base64", 6, SD_ENC_BASE64}, 63 + {"base64url", 9, SD_ENC_BASE64}, 64 + {NULL, 0, 0} 65 + }; 66 + for (int i = 0; map[i].label; i++) { 67 + if (len == map[i].llen && strncasecmp(s, map[i].label, len) == 0) 68 + return map[i].enc; 69 + } 70 + return SD_ENC_UTF8; 71 + } 72 + 73 + static const char *sd_encoding_name(int enc) { 74 + switch (enc) { 75 + case SD_ENC_UTF16LE: return "utf-16le"; 76 + case SD_ENC_LATIN1: return "latin1"; 77 + case SD_ENC_HEX: return "hex"; 78 + case SD_ENC_BASE64: return "base64"; 79 + default: return "utf-8"; 80 + }} 81 + 82 + static ant_value_t sd_latin1_to_str(ant_t *js, const uint8_t *src, size_t len) { 83 + char *out = malloc(len * 2 + 1); 84 + if (!out) return js_mkerr(js, "out of memory"); 85 + size_t o = 0; 86 + 87 + for (size_t i = 0; i < len; i++) { 88 + uint8_t b = src[i]; 89 + 90 + if (b < 0x80) out[o++] = (char)b; 91 + else { 92 + out[o++] = (char)(0xC0 | (b >> 6)); 93 + out[o++] = (char)(0x80 | (b & 0x3F)); 94 + }} 95 + 96 + ant_value_t result = js_mkstr(js, out, o); 97 + free(out); 98 + 99 + return result; 100 + } 101 + 102 + static ant_value_t sd_hex_decode(ant_t *js, const uint8_t *src, size_t len) { 103 + static const char hex[] = "0123456789abcdef"; 104 + if (len == 0) return js_mkstr(js, "", 0); 105 + 106 + char *out = malloc(len * 2 + 1); 107 + if (!out) return js_mkerr(js, "out of memory"); 108 + for (size_t i = 0; i < len; i++) { 109 + out[i*2] = hex[(src[i] >> 4) & 0xF]; 110 + out[i*2+1] = hex[src[i] & 0xF]; 111 + } 112 + 113 + ant_value_t result = js_mkstr(js, out, len * 2); 114 + free(out); 115 + 116 + return result; 117 + } 118 + 119 + static ant_value_t sd_base64_write(ant_t *js, sd_state_t *st, const uint8_t *src, size_t len, bool flush) { 120 + size_t total = (size_t)st->pending_len + len; 121 + if (total == 0) return js_mkstr(js, "", 0); 122 + 123 + uint8_t *work = malloc(total); 124 + if (!work) return js_mkerr(js, "out of memory"); 125 + 126 + if (st->pending_len > 0) 127 + memcpy(work, st->pending, (size_t)st->pending_len); 128 + if (src && len > 0) 129 + memcpy(work + st->pending_len, src, len); 130 + 131 + size_t encode_len = flush ? total : (total / 3) * 3; 132 + int new_pending = (int)(total - encode_len); 133 + 134 + ant_value_t result; 135 + if (encode_len == 0) result = js_mkstr(js, "", 0); else { 136 + size_t out_len; 137 + char *out = ant_base64_encode(work, encode_len, &out_len); 138 + if (!out) { free(work); return js_mkerr(js, "out of memory"); } 139 + result = js_mkstr(js, out, out_len); 140 + free(out); 141 + } 142 + 143 + st->pending_len = new_pending; 144 + if (new_pending > 0) 145 + memcpy(st->pending, work + encode_len, (size_t)new_pending); 146 + 147 + free(work); 148 + return result; 149 + } 150 + 151 + static ant_value_t sd_do_write(ant_t *js, sd_state_t *st, const uint8_t *src, size_t len, bool flush) { 152 + switch (st->encoding) { 153 + case SD_ENC_UTF8: 154 + case SD_ENC_UTF16LE: 155 + case SD_ENC_UTF16BE: 156 + return td_decode(js, st->td, src, len, !flush); 157 + case SD_ENC_LATIN1: 158 + if (!src || len == 0) return js_mkstr(js, "", 0); 159 + return sd_latin1_to_str(js, src, len); 160 + case SD_ENC_HEX: 161 + if (!src || len == 0) return js_mkstr(js, "", 0); 162 + return sd_hex_decode(js, src, len); 163 + case SD_ENC_BASE64: 164 + return sd_base64_write(js, st, src, len, flush); 165 + default: 166 + return js_mkstr(js, "", 0); 167 + }} 168 + 169 + static ant_value_t js_sd_get_encoding(ant_t *js, ant_value_t *args, int nargs) { 170 + sd_state_t *st = sd_get_state(js->this_val); 171 + if (!st) return js_mkstr(js, "utf-8", 5); 172 + const char *name = sd_encoding_name(st->encoding); 173 + return js_mkstr(js, name, strlen(name)); 174 + } 175 + 176 + static ant_value_t js_sd_write(ant_t *js, ant_value_t *args, int nargs) { 177 + sd_state_t *st = sd_get_state(js->this_val); 178 + 179 + if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); 180 + if (nargs < 1) return js_mkstr(js, "", 0); 181 + 182 + if (vtype(args[0]) == T_STR) { 183 + size_t slen; 184 + const char *s = js_getstr(js, args[0], &slen); 185 + return s ? js_mkstr(js, s, slen) : js_mkstr(js, "", 0); 186 + } 187 + 188 + const uint8_t *src = NULL; 189 + size_t len = 0; 190 + if (is_object_type(args[0])) 191 + buffer_source_get_bytes(js, args[0], &src, &len); 192 + 193 + return sd_do_write(js, st, src, len, false); 194 + } 195 + 196 + static ant_value_t js_sd_end(ant_t *js, ant_value_t *args, int nargs) { 197 + sd_state_t *st = sd_get_state(js->this_val); 198 + if (!st) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid StringDecoder"); 199 + 200 + const uint8_t *src = NULL; 201 + size_t len = 0; 202 + if (nargs > 0 && is_object_type(args[0])) 203 + buffer_source_get_bytes(js, args[0], &src, &len); 204 + 205 + return sd_do_write(js, st, src, len, true); 206 + } 207 + 208 + static ant_value_t js_sd_ctor(ant_t *js, ant_value_t *args, int nargs) { 209 + if (vtype(js->new_target) == T_UNDEF) 210 + return js_mkerr_typed(js, JS_ERR_TYPE, "StringDecoder constructor requires 'new'"); 211 + 212 + int enc = SD_ENC_UTF8; 213 + if (nargs > 0 && !is_undefined(args[0])) { 214 + ant_value_t label_val = (vtype(args[0]) == T_STR) ? args[0] : coerce_to_str(js, args[0]); 215 + if (!is_err(label_val) && vtype(label_val) == T_STR) { 216 + size_t llen; 217 + const char *label = js_getstr(js, label_val, &llen); 218 + if (label) enc = sd_parse_encoding(label, llen); 219 + }} 220 + 221 + sd_state_t *st = calloc(1, sizeof(sd_state_t)); 222 + if (!st) return js_mkerr(js, "out of memory"); 223 + st->encoding = enc; 224 + 225 + if (enc == SD_ENC_UTF8 || enc == SD_ENC_UTF16LE || enc == SD_ENC_UTF16BE) { 226 + td_encoding_t td_enc = (enc == SD_ENC_UTF16LE) ? TD_ENC_UTF16LE : (enc == SD_ENC_UTF16BE) ? TD_ENC_UTF16BE : TD_ENC_UTF8; 227 + st->td = td_state_new(td_enc, false, false); 228 + if (!st->td) { free(st); return js_mkerr(js, "out of memory"); } 229 + } 230 + 231 + ant_value_t obj = js_mkobj(js); 232 + ant_value_t proto = js_instance_proto_from_new_target(js, g_string_decoder_proto); 233 + 234 + if (is_object_type(proto)) js_set_proto_init(obj, proto); 235 + js_set_slot(obj, SLOT_DATA, ANT_PTR(st)); 236 + js_set_finalizer(obj, sd_finalize); 237 + 238 + return obj; 239 + } 240 + 241 + ant_value_t string_decoder_library(ant_t *js) { 242 + g_string_decoder_proto = js_mkobj(js); 243 + 244 + js_set_getter_desc(js, g_string_decoder_proto, "encoding", 8, js_mkfun(js_sd_get_encoding), JS_DESC_C); 245 + js_set(js, g_string_decoder_proto, "write", js_mkfun(js_sd_write)); 246 + js_set(js, g_string_decoder_proto, "end", js_mkfun(js_sd_end)); 247 + js_set_sym(js, g_string_decoder_proto, get_toStringTag_sym(), js_mkstr(js, "StringDecoder", 13)); 248 + 249 + ant_value_t ctor = js_make_ctor(js, js_sd_ctor, g_string_decoder_proto, "StringDecoder", 13); 250 + ant_value_t lib = js_mkobj(js); 251 + js_set(js, lib, "StringDecoder", ctor); 252 + 253 + return lib; 254 + }
+76 -47
src/modules/wasi.c
··· 7 7 #include "internal.h" 8 8 9 9 #include "ptr.h" 10 + #include "gc/roots.h" 10 11 #include "modules/buffer.h" 11 12 #include "modules/wasi.h" 12 13 #include "wasm_c_api.h" 13 14 #include "wasm_export.h" 15 + 16 + #define WASM_MAX_PARAMS 32 17 + #define WASM_MAX_ARGS 256 14 18 15 19 enum { 16 20 WASI_INSTANCE_TAG = 0x57415349u, // WASI ··· 38 42 39 43 uint32_t param_count = wasm_func_get_param_count(env->func, env->inst); 40 44 uint32_t result_count = wasm_func_get_result_count(env->func, env->inst); 45 + if (param_count > WASM_MAX_PARAMS) param_count = WASM_MAX_PARAMS; 41 46 42 - uint32_t wasm_argv[32]; 47 + uint32_t wasm_argv[WASM_MAX_PARAMS]; 43 48 memset(wasm_argv, 0, sizeof(wasm_argv)); 44 49 45 50 for (int i = 0; i < nargs && (uint32_t)i < param_count; i++) { ··· 58 63 static void wasi_instance_finalize(ant_t *js, ant_object_t *obj) { 59 64 if (obj->native.tag != WASI_INSTANCE_TAG) return; 60 65 wasi_instance_handle_t *handle = (wasi_instance_handle_t *)obj->native.ptr; 61 - 66 + 62 67 if (!handle) return; 63 68 if (handle->exec_env) wasm_runtime_destroy_exec_env(handle->exec_env); 64 69 if (handle->inst) wasm_runtime_deinstantiate(handle->inst); 65 70 if (handle->module) wasm_runtime_unload(handle->module); 66 - 71 + 67 72 free(handle->binary); 68 73 free(handle); 69 74 } ··· 84 89 return has_wasi; 85 90 } 86 91 92 + static void wasi_bind_func_export( 93 + ant_t *js, ant_value_t exports_obj, 94 + wasm_module_inst_t inst, wasm_exec_env_t exec_env, 95 + const char *name 96 + ) { 97 + wasm_function_inst_t func = wasm_runtime_lookup_function(inst, name); 98 + if (!func) return; 99 + 100 + wasi_func_env_t *fenv = calloc(1, sizeof(*fenv)); 101 + if (!fenv) return; 102 + fenv->js = js; 103 + fenv->inst = inst; 104 + fenv->exec_env = exec_env; 105 + fenv->func = func; 106 + 107 + GC_ROOT_SAVE(root_mark, js); 108 + ant_value_t obj = js_mkobj(js); 109 + GC_ROOT_PIN(js, obj); 110 + 111 + js_set_slot(obj, SLOT_CFUNC, js_mkfun(wasi_exported_func_call)); 112 + js_set_native_ptr(obj, fenv); 113 + js_set_native_tag(obj, WASI_FUNC_TAG); 114 + js_set(js, exports_obj, name, js_obj_to_func(obj)); 115 + GC_ROOT_RESTORE(js, root_mark); 116 + } 117 + 118 + static void wasi_bind_memory_export( 119 + ant_t *js, ant_value_t exports_obj, ant_value_t instance_obj, 120 + wasm_module_inst_t inst, const char *name 121 + ) { 122 + void *mem_data = wasm_runtime_addr_app_to_native(inst, 0); 123 + if (!mem_data) return; 124 + 125 + wasm_memory_inst_t mem = wasm_runtime_get_default_memory(inst); 126 + uint64_t pages = mem ? wasm_memory_get_cur_page_count(mem) : 0; 127 + size_t mem_size = (size_t)(pages * 65536); 128 + 129 + ArrayBufferData *buffer = calloc(1, sizeof(ArrayBufferData)); 130 + if (!buffer) return; 131 + 132 + buffer->data = (uint8_t *)mem_data; 133 + buffer->length = mem_size; 134 + buffer->capacity = mem_size; 135 + buffer->ref_count = 1; 136 + 137 + ant_value_t ab = create_arraybuffer_obj(js, buffer); 138 + ant_value_t mem_obj = js_mkobj(js); 139 + js_set_slot_wb(js, mem_obj, SLOT_DATA, ab); 140 + js_set_slot_wb(js, mem_obj, SLOT_CTOR, instance_obj); 141 + js_set(js, exports_obj, name, mem_obj); 142 + } 143 + 87 144 ant_value_t wasi_instantiate( 88 145 ant_t *js, const uint8_t *wasm_bytes, size_t wasm_len, 89 146 ant_value_t module_obj, ant_value_t wasi_opts 90 147 ) { 91 148 char error_buf[128] = {0}; 92 149 uint8_t *bin_copy = malloc(wasm_len); 93 - 150 + 94 151 if (!bin_copy) return js_mkerr(js, "out of memory"); 95 152 memcpy(bin_copy, wasm_bytes, wasm_len); 96 153 ··· 101 158 } 102 159 103 160 const char *dirs[] = { "." }; 104 - ant_value_t args_val = is_object_type(wasi_opts) 105 - ? js_get(js, wasi_opts, "args") 161 + ant_value_t args_val = is_object_type(wasi_opts) 162 + ? js_get(js, wasi_opts, "args") 106 163 : js_mkundef(); 107 - 164 + 108 165 int argc = vtype(args_val) == T_ARR ? (int)js_arr_len(js, args_val) : 0; 109 166 if (argc < 1) argc = 1; 167 + if (argc > WASM_MAX_ARGS) argc = WASM_MAX_ARGS; 110 168 111 169 char *argv[argc]; 112 170 if (vtype(args_val) == T_ARR) { 113 - for (int i = 0; i < argc; i++) 114 - argv[i] = js_getstr(js, js_arr_get(js, args_val, (ant_offset_t)i), NULL); 171 + for (int i = 0; i < argc; i++) { 172 + char *s = js_getstr(js, js_arr_get(js, args_val, (ant_offset_t)i), NULL); 173 + argv[i] = s ? s : (char *)""; 174 + } 115 175 } else argv[0] = (char *)"wasi"; 116 176 117 177 wasm_runtime_set_wasi_args(rt_module, dirs, 1, NULL, 0, NULL, 0, argv, argc); 118 178 wasm_module_inst_t inst = wasm_runtime_instantiate(rt_module, 512 * 1024, 256 * 1024, error_buf, sizeof(error_buf)); 119 - 179 + 120 180 if (!inst) { 121 181 wasm_runtime_unload(rt_module); 122 182 free(bin_copy); ··· 139 199 free(bin_copy); 140 200 return js_mkerr(js, "out of memory"); 141 201 } 142 - 202 + 143 203 handle->binary = bin_copy; 144 204 handle->module = rt_module; 145 205 handle->inst = inst; ··· 147 207 148 208 ant_value_t instance_obj = js_mkobj(js); 149 209 ant_value_t exports_obj = js_mkobj(js); 150 - 210 + 151 211 js_set_native_ptr(instance_obj, handle); 152 212 js_set_native_tag(instance_obj, WASI_INSTANCE_TAG); 153 213 js_set_slot_wb(js, instance_obj, SLOT_CTOR, module_obj); ··· 158 218 wasm_export_t export_info; 159 219 wasm_runtime_get_export_type(rt_module, i, &export_info); 160 220 161 - if (export_info.kind == WASM_IMPORT_EXPORT_KIND_FUNC) { 162 - wasm_function_inst_t func = wasm_runtime_lookup_function(inst, export_info.name); 163 - if (!func) continue; 164 - 165 - wasi_func_env_t *fenv = calloc(1, sizeof(*fenv)); 166 - if (!fenv) continue; 167 - fenv->js = js; 168 - fenv->inst = inst; 169 - fenv->exec_env = exec_env; 170 - fenv->func = func; 171 - 172 - ant_value_t obj = js_mkobj(js); 173 - js_set_slot(obj, SLOT_CFUNC, js_mkfun(wasi_exported_func_call)); 174 - js_set_native_ptr(obj, fenv); 175 - js_set_native_tag(obj, WASI_FUNC_TAG); 176 - js_set(js, exports_obj, export_info.name, js_obj_to_func(obj)); 177 - } 178 - else if (export_info.kind == WASM_IMPORT_EXPORT_KIND_MEMORY) { 179 - void *mem_data = wasm_runtime_addr_app_to_native(inst, 0); 180 - wasm_memory_inst_t mem = wasm_runtime_get_default_memory(inst); 181 - uint64_t pages = mem ? wasm_memory_get_cur_page_count(mem) : 0; 182 - size_t mem_size = (size_t)(pages * 65536); 183 - 184 - ArrayBufferData *buffer = calloc(1, sizeof(ArrayBufferData)); 185 - if (buffer && mem_data) { 186 - buffer->data = (uint8_t *)mem_data; 187 - buffer->length = mem_size; 188 - buffer->capacity = mem_size; 189 - buffer->ref_count = 1; 190 - ant_value_t ab = create_arraybuffer_obj(js, buffer); 191 - ant_value_t mem_obj = js_mkobj(js); 192 - js_set_slot_wb(js, mem_obj, SLOT_DATA, ab); 193 - js_set(js, exports_obj, export_info.name, mem_obj); 194 - } 195 - } 221 + if (export_info.kind == WASM_IMPORT_EXPORT_KIND_FUNC) 222 + wasi_bind_func_export(js, exports_obj, inst, exec_env, export_info.name); 223 + else if (export_info.kind == WASM_IMPORT_EXPORT_KIND_MEMORY) 224 + wasi_bind_memory_export(js, exports_obj, instance_obj, inst, export_info.name); 196 225 } 197 226 198 227 js_set_slot_wb(js, instance_obj, SLOT_ENTRIES, exports_obj);