util
This commit is contained in:
2
Makefile
2
Makefile
@@ -56,7 +56,7 @@ static:
|
||||
# Bootstrap: build cell from scratch using meson (only needed once)
|
||||
# Also installs core scripts to ~/.cell/core
|
||||
bootstrap:
|
||||
meson setup build_bootstrap -Dbuildtype=release
|
||||
meson setup build_bootstrap -Dbuildtype=debugoptimized
|
||||
meson compile -C build_bootstrap
|
||||
cp build_bootstrap/cell .
|
||||
cp build_bootstrap/libcell_runtime.dylib .
|
||||
|
||||
2
add.ce
2
add.ce
@@ -1,6 +1,6 @@
|
||||
// cell get <locator> [alias] - Add and install a package with its dependencies
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
|
||||
if (args.length < 1) {
|
||||
log.console("Usage: cell get <locator> [alias]")
|
||||
|
||||
2
build.ce
2
build.ce
@@ -6,7 +6,7 @@
|
||||
// cell build -t <target> Cross-compile dynamic libraries for target platform
|
||||
|
||||
var build = use('build')
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var pkg_tools = use('package')
|
||||
var fd = use('fd')
|
||||
|
||||
|
||||
2
build.cm
2
build.cm
@@ -11,7 +11,7 @@ var crypto = use('crypto')
|
||||
var utf8 = use('utf8')
|
||||
var os = use('os')
|
||||
var toolchains = use('toolchains')
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var pkg_tools = use('package')
|
||||
|
||||
var Build = {}
|
||||
|
||||
@@ -278,7 +278,7 @@ function mount_package(name) {
|
||||
return
|
||||
}
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var dir = shop.get_package_dir(name)
|
||||
|
||||
if (!dir) {
|
||||
@@ -475,7 +475,6 @@ cellfs.writepath = set_writepath
|
||||
cellfs.basedir = basedir
|
||||
cellfs.prefdir = prefdir
|
||||
cellfs.realdir = realdir
|
||||
cellfs.slurp = slurp
|
||||
|
||||
cellfs.mount('.')
|
||||
|
||||
|
||||
2
clean.ce
2
clean.ce
@@ -1,7 +1,7 @@
|
||||
// cell clean - Remove build artifacts from global shop
|
||||
|
||||
var fd = use('fd')
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
|
||||
var build_dir = shop.get_shop_path() + '/build'
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
var toml = use('toml')
|
||||
var pkg = use('package')
|
||||
var text = use('text')
|
||||
|
||||
function print_help() {
|
||||
log.console("Usage: cell config <command> [options]")
|
||||
@@ -80,7 +79,7 @@ function format_value(val) {
|
||||
// Add underscores to large numbers
|
||||
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '_')
|
||||
}
|
||||
return String(val)
|
||||
return text(val)
|
||||
}
|
||||
|
||||
// Print configuration tree recursively
|
||||
|
||||
4
fetch.ce
4
fetch.ce
@@ -8,7 +8,7 @@
|
||||
// cell fetch - Fetch all packages
|
||||
// cell fetch <package> - Fetch a specific package
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
|
||||
// Parse arguments
|
||||
var target_pkg = null
|
||||
@@ -67,7 +67,7 @@ for (var pkg of packages_to_fetch) {
|
||||
}
|
||||
|
||||
var result = shop.fetch(pkg)
|
||||
if (result && result.ok) {
|
||||
if (result) {
|
||||
if (result.zip_blob) {
|
||||
log.console("Fetched: " + pkg)
|
||||
success_count++
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// cell install <locator> - Install a package to the shop
|
||||
// Does not modify the current project's cell.toml
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var build = use('build')
|
||||
|
||||
if (args.length < 1) {
|
||||
|
||||
@@ -5,6 +5,7 @@ var _slice = Array.prototype.slice
|
||||
var _push = Array.prototype.push
|
||||
var _sort = Array.prototype.sort
|
||||
var _keys = Object.keys
|
||||
var _from = Array.from
|
||||
|
||||
function array(arg, arg2, arg3, arg4) {
|
||||
// array(number) - create array of size with nulls
|
||||
@@ -91,6 +92,9 @@ function array(arg, arg2, arg3, arg4) {
|
||||
|
||||
// array(object) - keys
|
||||
if (typeof arg == 'object' && arg != null && !_isArray(arg)) {
|
||||
if (arg instanceof Set) {
|
||||
return _from(arg)
|
||||
}
|
||||
return _keys(arg)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ delete globalThis.cell
|
||||
var ACTORDATA = _cell.hidden.actorsym
|
||||
var SYSYM = '__SYSTEM__'
|
||||
|
||||
var __cell = globalThis._cell
|
||||
|
||||
var hidden = _cell.hidden
|
||||
|
||||
var os = hidden.os;
|
||||
@@ -29,10 +27,19 @@ function use_embed(name) {
|
||||
return load_internal(`js_${name}_use`)
|
||||
}
|
||||
|
||||
globalThis.meme = function(obj) {
|
||||
return {
|
||||
globalThis.meme = function(obj, ...mixins) {
|
||||
var result = {
|
||||
__proto__: obj
|
||||
}
|
||||
|
||||
array.for(mixins, mix => {
|
||||
if (isa(mix, object)) {
|
||||
for (var key in mix) {
|
||||
result[key] = mix[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
globalThis.logical = function(val1)
|
||||
@@ -66,6 +73,11 @@ use_cache['core/os'] = os
|
||||
|
||||
var _Symbol = Symbol
|
||||
|
||||
globalThis.key = function()
|
||||
{
|
||||
return _Symbol()
|
||||
}
|
||||
|
||||
// Load a core module from the file system
|
||||
function use_core(path) {
|
||||
var cache_key = 'core/' + path
|
||||
@@ -392,7 +404,7 @@ os.use_cache = use_cache
|
||||
os.global_shop_path = shop_path
|
||||
os.$_ = $_
|
||||
|
||||
var shop = use_core('shop')
|
||||
var shop = use_core('internal/shop')
|
||||
|
||||
var json = use_core('json')
|
||||
var time = use_core('time')
|
||||
@@ -949,10 +961,6 @@ function enet_check()
|
||||
|
||||
// enet_check();
|
||||
|
||||
var init_end = time.number()
|
||||
|
||||
var load_program_start = time.number()
|
||||
|
||||
// Finally, run the program
|
||||
actor_mod.setname(_cell.args.program)
|
||||
|
||||
@@ -1005,8 +1013,8 @@ delete globalThis.WeakSet
|
||||
delete globalThis.WeakRef
|
||||
delete globalThis.BigInt
|
||||
delete globalThis.Symbol
|
||||
delete globalThis.Map
|
||||
delete globalThis.Set
|
||||
//delete globalThis.Map
|
||||
//delete globalThis.Set
|
||||
delete globalThis.Promise
|
||||
delete globalThis.ArrayBuffer
|
||||
delete globalThis.DataView
|
||||
|
||||
@@ -326,7 +326,7 @@ static JSValue js_os_dylib_open(JSContext *js, JSValue self, int argc, JSValue *
|
||||
#ifdef _WIN32
|
||||
handle = LoadLibraryA(path);
|
||||
#else
|
||||
handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
handle = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
||||
#endif
|
||||
|
||||
JS_FreeCString(js, path);
|
||||
|
||||
@@ -99,6 +99,11 @@ function get_import_package(name) {
|
||||
return null
|
||||
}
|
||||
|
||||
function is_internal_path(path)
|
||||
{
|
||||
return path && path.startsWith('internal/')
|
||||
}
|
||||
|
||||
function split_explicit_package_import(path)
|
||||
{
|
||||
if (!path) return null
|
||||
@@ -429,6 +434,10 @@ function resolve_mod_fn(path, pkg) {
|
||||
function resolve_locator(path, ctx)
|
||||
{
|
||||
var explicit = split_explicit_package_import(path)
|
||||
if (explicit) {
|
||||
if (is_internal_path(explicit.path) && ctx && explicit.package != ctx)
|
||||
explicit = null
|
||||
}
|
||||
if (explicit) {
|
||||
var explicit_path = get_packages_dir() + '/' + safe_package_path(explicit.package) + '/' + explicit.path
|
||||
if (fd.is_file(explicit_path)) {
|
||||
@@ -456,6 +465,9 @@ function resolve_locator(path, ctx)
|
||||
return {path: ctx_path, scope: SCOPE_LOCAL, symbol: fn}
|
||||
}
|
||||
|
||||
if (is_internal_path(path))
|
||||
return null
|
||||
|
||||
// check for aliased dependency
|
||||
var alias = pkg_tools.split_alias(ctx, path)
|
||||
if (alias) {
|
||||
@@ -510,16 +522,20 @@ function get_lib_path(pkg) {
|
||||
// Resolve a C symbol by searching:
|
||||
// 1. If package_context is null, only check core internal symbols
|
||||
// 2. Otherwise: own package (internal then dylib) -> other packages (internal then dylib) -> core (internal only)
|
||||
// Core is never loaded as a dynamic library via dlopen
|
||||
function resolve_c_symbol(path, package_context)
|
||||
{
|
||||
var explicit = split_explicit_package_import(path)
|
||||
if (explicit) {
|
||||
var sym = make_c_symbol(explicit.package, explicit.path)
|
||||
if (os.internal_exists(sym)) {
|
||||
return {
|
||||
symbol: function() { return os.load_internal(sym) },
|
||||
scope: SCOPE_PACKAGE,
|
||||
// Core is never loaded as a dynamic library via dlopen
|
||||
function resolve_c_symbol(path, package_context)
|
||||
{
|
||||
var explicit = split_explicit_package_import(path)
|
||||
if (explicit) {
|
||||
if (is_internal_path(explicit.path) && package_context && explicit.package != package_context)
|
||||
explicit = null
|
||||
}
|
||||
if (explicit) {
|
||||
var sym = make_c_symbol(explicit.package, explicit.path)
|
||||
if (os.internal_exists(sym)) {
|
||||
return {
|
||||
symbol: function() { return os.load_internal(sym) },
|
||||
scope: SCOPE_PACKAGE,
|
||||
package: explicit.package,
|
||||
path: sym
|
||||
}
|
||||
@@ -575,6 +591,9 @@ function resolve_c_symbol(path, package_context)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_internal_path(path))
|
||||
return null
|
||||
|
||||
// 2. Check aliased package imports (e.g. 'prosperon/sprite')
|
||||
var pkg_alias = get_import_package(path)
|
||||
if (pkg_alias) {
|
||||
@@ -622,7 +641,15 @@ function resolve_c_symbol(path, package_context)
|
||||
return null
|
||||
}
|
||||
|
||||
// Cache for resolved module info
|
||||
var module_info_cache = {}
|
||||
|
||||
function resolve_module_info(path, package_context) {
|
||||
var lookup_key = package_context ? package_context + ':' + path : ':' + path
|
||||
|
||||
if (module_info_cache[lookup_key])
|
||||
return module_info_cache[lookup_key]
|
||||
|
||||
var c_resolve = resolve_c_symbol(path, package_context) || {scope:999}
|
||||
var mod_resolve = resolve_locator(path + '.cm', package_context) || {scope:999}
|
||||
var min_scope = number.min(c_resolve.scope, mod_resolve.scope)
|
||||
@@ -630,58 +657,49 @@ function resolve_module_info(path, package_context) {
|
||||
if (min_scope == 999)
|
||||
return null
|
||||
|
||||
// Cache key is based on the realpath of the resolved file
|
||||
// This ensures linked packages resolve to the same cache entry
|
||||
// whether accessed via symlink or directly
|
||||
var cache_key
|
||||
if (mod_resolve.scope == SCOPE_CORE) {
|
||||
cache_key = 'core/' + path
|
||||
} else if (mod_resolve.scope < 900 && mod_resolve.path) {
|
||||
// Use realpath to resolve symlinks and get the actual file location
|
||||
var real_path = fd.realpath(mod_resolve.path)
|
||||
if (real_path) {
|
||||
// Derive cache key from the real path's package info
|
||||
var real_info = Shop.file_info(real_path)
|
||||
if (real_info.package && real_info.name) {
|
||||
if (real_info.package && real_info.name)
|
||||
cache_key = real_info.package + '/' + real_info.name
|
||||
} else {
|
||||
// Fallback to the realpath itself
|
||||
else
|
||||
cache_key = real_path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for C-only modules or if realpath failed
|
||||
if (!cache_key) {
|
||||
if (min_scope == SCOPE_CORE) {
|
||||
if (min_scope == SCOPE_CORE)
|
||||
cache_key = 'core/' + path
|
||||
} else if (min_scope == SCOPE_LOCAL && package_context) {
|
||||
else if (min_scope == SCOPE_LOCAL && package_context)
|
||||
cache_key = package_context + '/' + path
|
||||
} else if (min_scope == SCOPE_PACKAGE) {
|
||||
// For package imports like 'prosperon/sprite', resolve to canonical path
|
||||
else if (min_scope == SCOPE_PACKAGE) {
|
||||
var pkg_alias = get_import_package(path)
|
||||
if (pkg_alias) {
|
||||
var canon_pkg = get_canonical_package(pkg_alias, package_context)
|
||||
if (canon_pkg) {
|
||||
var mod_name = get_import_name(path)
|
||||
cache_key = canon_pkg + '/' + mod_name
|
||||
} else {
|
||||
} else
|
||||
cache_key = path
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
cache_key = path
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
cache_key = path
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
var info = {
|
||||
cache_key: cache_key,
|
||||
c_resolve: c_resolve,
|
||||
mod_resolve: mod_resolve,
|
||||
min_scope: min_scope
|
||||
}
|
||||
|
||||
module_info_cache[lookup_key] = info
|
||||
return info
|
||||
}
|
||||
|
||||
function get_module_cache_key(path, package_context) {
|
||||
@@ -689,7 +707,7 @@ function get_module_cache_key(path, package_context) {
|
||||
return info ? info.cache_key : null
|
||||
}
|
||||
|
||||
Shop.is_loaded = function(path, package_context) {
|
||||
Shop.is_loaded = function is_loaded(path, package_context) {
|
||||
var cache_key = get_module_cache_key(path, package_context)
|
||||
return use_cache[cache_key] != null
|
||||
}
|
||||
@@ -732,7 +750,7 @@ function execute_module(info)
|
||||
} if (!used)
|
||||
throw new Error(`Module ${info} returned null`)
|
||||
|
||||
stone(used)
|
||||
// stone(used)
|
||||
return used
|
||||
}
|
||||
|
||||
@@ -745,7 +763,7 @@ function get_module(path, package_context) {
|
||||
return execute_module(info)
|
||||
}
|
||||
|
||||
Shop.use = function(path, package_context) {
|
||||
Shop.use = function use(path, package_context) {
|
||||
var info = resolve_module_info(path, package_context)
|
||||
if (!info)
|
||||
throw new Error(`Module ${path} could not be found in ${package_context}`)
|
||||
@@ -1034,6 +1052,11 @@ Shop.file_reload = function(file)
|
||||
|
||||
Shop.module_reload = function(path, package) {
|
||||
if (!Shop.is_loaded(path,package)) return
|
||||
|
||||
// Clear the module info cache for this path
|
||||
var lookup_key = package ? package + ':' + path : ':' + path
|
||||
module_info_cache[lookup_key] = null
|
||||
|
||||
var info = resolve_module_info(path, package)
|
||||
if (!info) return
|
||||
|
||||
@@ -1044,10 +1067,9 @@ Shop.module_reload = function(path, package) {
|
||||
for (var i in newmod)
|
||||
old[i] = newmod[i]
|
||||
|
||||
for (var i in old) {
|
||||
for (var i in old)
|
||||
if (!(i in newmod))
|
||||
old[i] = null
|
||||
}
|
||||
}
|
||||
|
||||
function get_package_scripts(package)
|
||||
2
link.ce
2
link.ce
@@ -13,7 +13,7 @@
|
||||
// cell link gitea.pockle.world/john/prosperon github.com/prosperon (Links to another remote)
|
||||
|
||||
var link = use('link')
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var fd = use('fd')
|
||||
var toml = use('toml')
|
||||
|
||||
|
||||
2
list.ce
2
list.ce
@@ -3,7 +3,7 @@
|
||||
// cell list all -> list all packages (including those that are there due to installed packages)
|
||||
// cell list package <name> -> list the packages for the package <name>
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var pkg = use('package')
|
||||
|
||||
var mode = 'local'
|
||||
|
||||
2
ls.ce
2
ls.ce
@@ -2,7 +2,7 @@
|
||||
// if args[0] is a package alias, list that one
|
||||
// otherwise, list the local one
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var package = use('package')
|
||||
|
||||
var ctx = null
|
||||
|
||||
2
pack.ce
2
pack.ce
@@ -6,7 +6,7 @@
|
||||
// cell pack <package> -t <target> Cross-compile for target platform
|
||||
|
||||
var build = use('build')
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var pkg_tools = use('package')
|
||||
|
||||
var target = null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// cell remove <alias|path> - Remove a package from dependencies or shop
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
|
||||
if (args.length < 1) {
|
||||
log.console("Usage: cell remove <alias|path>")
|
||||
|
||||
@@ -275,6 +275,11 @@ double cell_random() {
|
||||
return (double)buf / 9007199254740992.0;
|
||||
}
|
||||
|
||||
void cell_trace_sethook(cell_hook)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int uncaught_exception(JSContext *js, JSValue v)
|
||||
{
|
||||
cell_rt *rt = JS_GetContextOpaque(js);
|
||||
|
||||
@@ -28,6 +28,11 @@ JSValue number2js(JSContext *js, double g);
|
||||
JSValue wota2value(JSContext *js, void *v);
|
||||
void *value2wota(JSContext *js, JSValue v, JSValue replacer, size_t *bytes);
|
||||
|
||||
#define CELL_HOOK_ENTER 1
|
||||
#define CELL_HOOK_EXIT 2
|
||||
typedef void (*cell_hook)(const char *name, int type);
|
||||
void cell_trace_sethook(cell_hook);
|
||||
|
||||
// Macros to help with creating scripts
|
||||
#define MIST_CFUNC_DEF(name, length, func1, props) { name, props, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ typedef struct cell_rt {
|
||||
JSAtom actor_sym;
|
||||
|
||||
const char *name; // human friendly name
|
||||
cell_hook trace_hook;
|
||||
} cell_rt;
|
||||
|
||||
cell_rt *create_actor(void *wota);
|
||||
|
||||
109
source/quickjs.c
109
source/quickjs.c
@@ -340,11 +340,9 @@ struct JSContext {
|
||||
const char *filename, int flags, int scope_idx);
|
||||
void *user_opaque;
|
||||
|
||||
js_hook fn_start_hook;
|
||||
js_hook fn_end_hook;
|
||||
js_hook fn_cycle_hook;
|
||||
js_hook fn_gc_hook;
|
||||
int hook_disabled;
|
||||
js_hook trace_hook;
|
||||
int trace_type;
|
||||
void *trace_data;
|
||||
};
|
||||
|
||||
typedef union JSFloat64Union {
|
||||
@@ -1569,9 +1567,11 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
|
||||
int i;
|
||||
|
||||
ctx = js_mallocz_rt(rt, sizeof(JSContext));
|
||||
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
ctx->header.ref_count = 1;
|
||||
ctx->trace_hook = NULL;
|
||||
add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
|
||||
|
||||
ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
|
||||
@@ -1586,7 +1586,6 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
|
||||
ctx->class_proto[i] = JS_NULL;
|
||||
ctx->array_ctor = JS_NULL;
|
||||
ctx->regexp_ctor = JS_NULL;
|
||||
|
||||
JS_AddIntrinsicBasicObjects(ctx);
|
||||
rt->js = ctx;
|
||||
return ctx;
|
||||
@@ -5943,6 +5942,38 @@ static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return a string property without executing arbitrary JS code (used
|
||||
when dumping the stack trace or in debug print). */
|
||||
static const char *get_prop_string(JSContext *ctx, JSValueConst obj, JSAtom prop)
|
||||
{
|
||||
JSObject *p;
|
||||
JSProperty *pr;
|
||||
JSShapeProperty *prs;
|
||||
JSValueConst val;
|
||||
|
||||
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
|
||||
return NULL;
|
||||
p = JS_VALUE_GET_OBJ(obj);
|
||||
prs = find_own_property(&pr, p, prop);
|
||||
if (!prs) {
|
||||
/* we look at one level in the prototype to handle the 'name'
|
||||
field of the Error objects */
|
||||
p = p->shape->proto;
|
||||
if (!p)
|
||||
return NULL;
|
||||
prs = find_own_property(&pr, p, prop);
|
||||
if (!prs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
|
||||
return NULL;
|
||||
val = pr->u.value;
|
||||
if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
|
||||
return NULL;
|
||||
return JS_ToCString(ctx, val);
|
||||
}
|
||||
|
||||
/* in order to avoid executing arbitrary code during the stack trace
|
||||
generation, we only look at simple 'name' properties containing a
|
||||
string. */
|
||||
@@ -5962,7 +5993,9 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func)
|
||||
val = pr->u.value;
|
||||
if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
|
||||
return NULL;
|
||||
return JS_ToCString(ctx, val);
|
||||
|
||||
// char *buf = js_malloc(ctx->rt, 128);
|
||||
// return JS_AtomGetStr(ctx, buf, 128, prs->atom);
|
||||
}
|
||||
|
||||
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
|
||||
@@ -12222,10 +12255,11 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
||||
|
||||
func = p->u.cfunc.c_function;
|
||||
|
||||
if (unlikely(ctx->fn_start_hook) && !ctx->hook_disabled) {
|
||||
ctx->hook_disabled = 1;
|
||||
ctx->fn_start_hook(ctx,func_obj);
|
||||
ctx->hook_disabled = 0;
|
||||
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_CALL)) {
|
||||
js_debug dbg = {0};
|
||||
js_debug_info(ctx, func_obj, &dbg);
|
||||
ctx->trace_hook(ctx, JS_HOOK_CALL, &dbg, ctx->trace_data);
|
||||
free_js_debug_info(ctx, &dbg);
|
||||
}
|
||||
|
||||
switch(cproto) {
|
||||
@@ -12312,13 +12346,14 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
||||
}
|
||||
|
||||
rt->current_stack_frame = sf->prev_frame;
|
||||
|
||||
if (unlikely(ctx->fn_end_hook) && !ctx->hook_disabled) {
|
||||
ctx->hook_disabled = 1;
|
||||
ctx->fn_end_hook(ctx, func_obj);
|
||||
ctx->hook_disabled = 0;
|
||||
|
||||
if (unlikely(ctx->trace_hook) && (ctx->trace_type & JS_HOOK_RET)) {
|
||||
js_debug dbg = {0};
|
||||
js_debug_info(ctx, func_obj, &dbg);
|
||||
ctx->trace_hook(ctx, JS_HOOK_RET, &dbg, ctx->trace_data);
|
||||
free_js_debug_info(ctx, &dbg);
|
||||
}
|
||||
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
@@ -12418,10 +12453,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
}
|
||||
b = p->u.func.function_bytecode;
|
||||
|
||||
if (unlikely(caller_ctx->fn_start_hook) && !caller_ctx->hook_disabled) {
|
||||
caller_ctx->hook_disabled = 1;
|
||||
caller_ctx->fn_start_hook(caller_ctx,func_obj);
|
||||
caller_ctx->hook_disabled = 0;
|
||||
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_CALL)) {
|
||||
js_debug dbg = {0};
|
||||
js_debug_info(caller_ctx, func_obj, &dbg);
|
||||
caller_ctx->trace_hook(caller_ctx, JS_HOOK_CALL, &dbg, caller_ctx->trace_data);
|
||||
free_js_debug_info(caller_ctx, &dbg);
|
||||
}
|
||||
|
||||
if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
|
||||
@@ -14584,11 +14620,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
}
|
||||
rt->current_stack_frame = sf->prev_frame;
|
||||
|
||||
if (unlikely(caller_ctx->fn_end_hook) && !caller_ctx->hook_disabled) {
|
||||
caller_ctx->hook_disabled = 1;
|
||||
caller_ctx->fn_end_hook(caller_ctx,func_obj);
|
||||
caller_ctx->hook_disabled = 0;
|
||||
}
|
||||
if (unlikely(caller_ctx->trace_hook) && (caller_ctx->trace_type & JS_HOOK_RET)) {
|
||||
js_debug dbg = {0};
|
||||
js_debug_info(caller_ctx, func_obj, &dbg);
|
||||
caller_ctx->trace_hook(caller_ctx, JS_HOOK_RET, &dbg, caller_ctx->trace_data);
|
||||
free_js_debug_info(caller_ctx, &dbg);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
@@ -36834,7 +36871,7 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
|
||||
if (!JS_IsObject(fn)) return;
|
||||
JSObject *p = JS_VALUE_GET_OBJ(fn);
|
||||
|
||||
const char *fn_name = get_func_name(js,fn);
|
||||
const char *fn_name = get_prop_string(js, fn, JS_ATOM_name);
|
||||
|
||||
if (!fn_name)
|
||||
dbg->name = js_strdup(js, "<anonymous>");
|
||||
@@ -36867,7 +36904,8 @@ void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg)
|
||||
dbg->closure_n = b->closure_var_count;
|
||||
dbg->param_n = b->arg_count;
|
||||
dbg->vararg = 1;
|
||||
// dbg->line = b->debug.line_num;
|
||||
int pcol_num;
|
||||
dbg->line = find_line_num(js, b, -1, &pcol_num);
|
||||
dbg->source = b->debug.source;
|
||||
dbg->srclen = b->debug.source_len;
|
||||
break;
|
||||
@@ -36890,16 +36928,11 @@ void free_js_debug_info(JSContext *js, js_debug *dbg)
|
||||
js_free(js, dbg->name);
|
||||
}
|
||||
|
||||
void js_debug_sethook(JSContext *ctx, js_hook hook, int type)
|
||||
void js_debug_sethook(JSContext *ctx, js_hook hook, int type, void *user)
|
||||
{
|
||||
if (type == JS_HOOK_CALL)
|
||||
ctx->fn_start_hook = hook;
|
||||
else if (type == JS_HOOK_RET)
|
||||
ctx->fn_end_hook = hook;
|
||||
else if (type == JS_HOOK_CYCLE)
|
||||
ctx->fn_cycle_hook = hook;
|
||||
else if (type == JS_HOOK_GC)
|
||||
ctx->fn_gc_hook = hook;
|
||||
ctx->trace_hook = hook;
|
||||
ctx->trace_type = type;
|
||||
ctx->trace_data = user;
|
||||
}
|
||||
|
||||
uint32_t js_debugger_stack_depth(JSContext *ctx) {
|
||||
@@ -37502,4 +37535,4 @@ void *js_debugger_val_address(JSContext *ctx, JSValue val) {
|
||||
|
||||
JSContext *JS_GetContext(JSRuntime *rt) {
|
||||
return rt->js;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,7 +961,6 @@ void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_o
|
||||
void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,
|
||||
JSValueConst val, const JSPrintValueOptions *options);
|
||||
|
||||
|
||||
typedef struct js_debug {
|
||||
const char *name; // nameof function
|
||||
const char *what;
|
||||
@@ -979,12 +978,12 @@ typedef struct js_debug {
|
||||
void js_debug_info(JSContext *js, JSValue fn, js_debug *dbg);
|
||||
void free_js_debug_info(JSContext *js, js_debug *dbg);
|
||||
|
||||
typedef void (*js_hook)(JSContext*, JSValue);
|
||||
#define JS_HOOK_CALL 0
|
||||
#define JS_HOOK_RET 1
|
||||
#define JS_HOOK_CYCLE 2
|
||||
#define JS_HOOK_GC 3
|
||||
void js_debug_sethook(JSContext *ctx, js_hook, int type);
|
||||
typedef void (*js_hook)(JSContext*, int type, js_debug *dbg, void *user);
|
||||
#define JS_HOOK_CALL 1
|
||||
#define JS_HOOK_RET 2
|
||||
#define JS_HOOK_CYCLE 4
|
||||
#define JS_HOOK_GC 8
|
||||
void js_debug_sethook(JSContext *ctx, js_hook, int type, void *user);
|
||||
|
||||
uint32_t js_debugger_stack_depth(JSContext *ctx);
|
||||
JSValue js_debugger_backtrace_fns(JSContext *ctx, const uint8_t *cur_pc);
|
||||
|
||||
@@ -259,12 +259,7 @@ void actor_initialize(void) {
|
||||
void actor_free(cell_rt *actor)
|
||||
{
|
||||
lockless_shdel(actors, actor->id);
|
||||
|
||||
// Note: Removing from ready queue is hard with a singly linked list.
|
||||
// We assume actor_turn handles disrupted/freed actors gracefully or they run once more.
|
||||
// The old code did lockless_rm(ready_queue, actor), which was O(N).
|
||||
// Here we rely on the actor->disrupt flag checked in actor_turn.
|
||||
|
||||
|
||||
// Do not go forward with actor destruction until the actor is completely free
|
||||
pthread_mutex_lock(actor->msg_mutex);
|
||||
pthread_mutex_lock(actor->mutex);
|
||||
@@ -539,10 +534,6 @@ const char *register_actor(const char *id, cell_rt *actor, int mainthread, doubl
|
||||
|
||||
int actor_interrupt_cb(JSRuntime *rt, cell_rt *crt)
|
||||
{
|
||||
// Locking engine.lock for shutting_down might be too expensive for interrupt?
|
||||
// Check atomic-like access or just access it.
|
||||
// int s; pthread_mutex_lock(&engine.lock); s = engine.shutting_down; pthread_mutex_unlock(&engine.lock);
|
||||
// But engine.shutting_down is int, atomic read on x86/arm usually ok.
|
||||
return engine.shutting_down || crt->disrupt;
|
||||
}
|
||||
|
||||
@@ -573,10 +564,12 @@ const char *send_message(const char *id, void *msg)
|
||||
void actor_turn(cell_rt *actor)
|
||||
{
|
||||
pthread_mutex_lock(actor->mutex);
|
||||
|
||||
|
||||
actor->state = ACTOR_RUNNING;
|
||||
|
||||
actor->state = ACTOR_RUNNING;
|
||||
|
||||
if (actor->trace_hook)
|
||||
actor->trace_hook(actor->name, CELL_HOOK_ENTER);
|
||||
|
||||
TAKETURN:
|
||||
|
||||
pthread_mutex_lock(actor->msg_mutex);
|
||||
@@ -605,20 +598,12 @@ void actor_turn(cell_rt *actor)
|
||||
|
||||
if (actor->disrupt) goto ENDTURN;
|
||||
|
||||
// Check if anyone else is waiting?
|
||||
// In the new system, checking the global queue is expensive (lock).
|
||||
// And "someone else waiting" logic was to yield.
|
||||
// With threads, we don't need to yield as much, let the OS schedule.
|
||||
// But we might want to prevent one actor hogging the worker?
|
||||
// For now, remove the yield check or implement it with try_lock or simple check.
|
||||
// int someone_else_waiting = (lockless_arrlen(ready_queue) > 0);
|
||||
// We'll just remove the optimization/yield for now to simplify.
|
||||
// if (!someone_else_waiting) goto TAKETURN;
|
||||
|
||||
ENDTURN:
|
||||
actor->state = ACTOR_IDLE;
|
||||
|
||||
actor->state = ACTOR_IDLE;
|
||||
|
||||
if (actor->trace_hook)
|
||||
actor->trace_hook(actor->name, CELL_HOOK_EXIT);
|
||||
|
||||
set_actor_state(actor);
|
||||
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
|
||||
2
test.ce
2
test.ce
@@ -1,4 +1,4 @@
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var fd = use('fd')
|
||||
var time = use('time')
|
||||
var json = use('json')
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
var text = use('text')
|
||||
|
||||
return {
|
||||
// Array conversion tests
|
||||
test_array_basic: function() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
var text = use('text');
|
||||
var blob = use('blob');
|
||||
var utf8 = use('utf8');
|
||||
|
||||
|
||||
4
toml.cm
4
toml.cm
@@ -146,7 +146,7 @@ function encode_toml(obj) {
|
||||
} else if (typeof value == 'boolean') {
|
||||
return value ? 'true' : 'false'
|
||||
} else if (typeof value == 'number') {
|
||||
return String(value)
|
||||
return text(value)
|
||||
} else if (isa(value, array)) {
|
||||
var items = []
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
@@ -154,7 +154,7 @@ function encode_toml(obj) {
|
||||
}
|
||||
return '[' + items.join(', ') + ']'
|
||||
}
|
||||
return String(value)
|
||||
return text(value)
|
||||
}
|
||||
|
||||
function quote_key(k) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// cell update - Update all packages
|
||||
// cell update <package> - Update a specific package
|
||||
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
|
||||
var target_pkg = null
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var shop = use('shop')
|
||||
var shop = use('internal/shop')
|
||||
var fd = use('fd')
|
||||
|
||||
var cmd = args.length > 0 ? args[0] : null
|
||||
|
||||
5
util.cm
Normal file
5
util.cm
Normal file
@@ -0,0 +1,5 @@
|
||||
var shop = use('internal/shop')
|
||||
|
||||
return {
|
||||
file_reload: shop.file_reload
|
||||
}
|
||||
Reference in New Issue
Block a user