Compare commits
2 Commits
stack
...
js-rm-coer
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94394c6845 | ||
|
|
b33c7adb07 |
@@ -6,7 +6,7 @@ ar_timer = 60
|
||||
actor_memory = 0
|
||||
net_service = 0.1
|
||||
reply_timeout = 60
|
||||
actor_max = "10_000"
|
||||
actor_max = 10_000
|
||||
stack_max = 0
|
||||
[actors]
|
||||
[actors.prosperon/sdl_video]
|
||||
|
||||
4
cell.md
4
cell.md
@@ -2,6 +2,10 @@ JAVASCRIPT VISION
|
||||
|
||||
I see objects as being a sort of combination of a lisp cell and a record: symbols, which are used internally, and are private and non iterable, and record string values, which are iterable, readable, and writable; of course everything becomes locked in when stone.
|
||||
|
||||
This lets the runtime have its own set of symbols, accessible via "cell.+", "cell.-", etc.
|
||||
|
||||
but then you can also have modules, imported via use, which expose their own symbols: use('math') can give you a set of symbols like "torads", which you can then define on your objects to specify how they should react to "torads".
|
||||
|
||||
CELLSCRIPT
|
||||
|
||||
Javascript to its core. Objects. What does the language need? It can be quite small, I think. The key is, ANYTHING that we want to be fast and JIT'd, must be present. So, record lookups. These are actually quicker in a jit'd language that have them as a feature. Most things should be libraries. Blobs need to be in the runtime.
|
||||
|
||||
@@ -310,7 +310,7 @@ var input_state = {
|
||||
|
||||
// 1) input runs completely independently
|
||||
function poll_input() {
|
||||
send(video, {kind:'input', op:'get'}, evs => {
|
||||
send(video, {kind:'input', op:'get'}, (evs=[]) => {
|
||||
for (var ev of evs) {
|
||||
if (ev.type == 'quit')
|
||||
$_.stop()
|
||||
|
||||
@@ -117,7 +117,9 @@ $_.receiver(function(msg) {
|
||||
response = {error: "Unknown kind: " + msg.kind};
|
||||
}
|
||||
} catch (e) {
|
||||
response = {error: e.toString()};
|
||||
log.console(typeof e)
|
||||
log.console(typeof null)
|
||||
response = {error: e};
|
||||
log.error(e)
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ config.system ??= {}
|
||||
config.system.__proto__ = default_config
|
||||
|
||||
ENETSERVICE = config.system.net_service
|
||||
REPLYTIMEOUT = config.system.reply_timeout
|
||||
REPLYTIMEOUT = Number(config.system.reply_timeout)
|
||||
|
||||
globalThis.text = use('text')
|
||||
|
||||
@@ -353,14 +353,13 @@ function guid(bits = 256)
|
||||
|
||||
var HEADER = Symbol()
|
||||
|
||||
function create_actor(desc = {id:guid()}) {
|
||||
function create_actor(defn = {id:guid()}) {
|
||||
var actor = {}
|
||||
actor[ACTORDATA] = desc
|
||||
actor[ACTORDATA] = defn
|
||||
return actor
|
||||
}
|
||||
|
||||
var $_ = create_actor()
|
||||
|
||||
$_.random = hidden.rand
|
||||
$_.random[cell.DOC] = "returns a number between 0 and 1. There is a 50% chance that the result is less than 0.5."
|
||||
|
||||
@@ -511,6 +510,7 @@ $_.start = function start(cb, program, ...args) {
|
||||
|
||||
$_.stop = function stop(actor) {
|
||||
if (!actor) {
|
||||
log.system(`actor stopping.`)
|
||||
need_stop = true
|
||||
return
|
||||
}
|
||||
@@ -608,6 +608,7 @@ function actor_send(actor, message) {
|
||||
return
|
||||
}
|
||||
log.system(`Unable to send message to actor ${json.encode(actor[ACTORDATA])}`)
|
||||
log.system(`message was ${json.encode(message)}`)
|
||||
}
|
||||
|
||||
// Holds all messages queued during the current turn.
|
||||
@@ -678,13 +679,13 @@ function turn(msg)
|
||||
|
||||
load_actor_config(cell.args.program)
|
||||
|
||||
actor_mod.register_actor(cell.id, turn, cell.args.main, config.system.ar_timer)
|
||||
actor_mod.register_actor(cell.id, turn, cell.args.main, 60)
|
||||
|
||||
if (config.system.actor_memory)
|
||||
js.mem_limit(config.system.actor_memory)
|
||||
if (Number(config.system.actor_memory))
|
||||
js.mem_limit(Number(config.system.actor_memory))
|
||||
|
||||
if (config.system.stack_max)
|
||||
js.max_stacksize(config.system.stack_max);
|
||||
js.max_stacksize(Number(config.system.stack_max))
|
||||
|
||||
overling = cell.args.overling
|
||||
root = cell.args.root
|
||||
|
||||
@@ -117,6 +117,7 @@ static void exit_handler(void)
|
||||
void actor_free(cell_rt *actor)
|
||||
{
|
||||
// Delete it out of actors first so it can no longer get messages
|
||||
printf("killing off %s\n", actor->id);
|
||||
SDL_LockMutex(actors_mutex);
|
||||
shdel(actors, actor->id);
|
||||
int remaining = shlen(actors);
|
||||
@@ -788,8 +789,20 @@ int uncaught_exception(JSContext *js, JSValue v)
|
||||
}
|
||||
|
||||
JSValue exp = JS_GetException(js);
|
||||
JSValue ret = JS_Call(js, rt->on_exception, JS_NULL, 1, &exp);
|
||||
JS_FreeValue(js,ret);
|
||||
|
||||
if (JS_IsNull(rt->on_exception)) {
|
||||
JSValue stack = JS_GetPropertyStr(js, exp, "stack");
|
||||
const char *ss = JS_ToCString(js,stack);
|
||||
const char *se = JS_ToCString(js, exp);
|
||||
printf("Uncaught exception %s:\n%s\n", se, ss);
|
||||
JS_FreeCString(js,ss);
|
||||
JS_FreeCString(js,se);
|
||||
JS_FreeValue(js,stack);
|
||||
} else {
|
||||
JSValue ret = JS_Call(js, rt->on_exception, JS_NULL, 1, &exp);
|
||||
JS_FreeValue(js,ret);
|
||||
}
|
||||
|
||||
JS_FreeValue(js, exp);
|
||||
JS_FreeValue(js,v);
|
||||
SDL_UnlockMutex(rt->mutex);
|
||||
|
||||
@@ -180,7 +180,11 @@ int js2bool(JSContext *js, JSValue v) { return JS_ToBool(js,v); }
|
||||
JSValue number2js(JSContext *js, double g) { return JS_NewFloat64(js,g); }
|
||||
double js2number(JSContext *js, JSValue v) {
|
||||
double g;
|
||||
JS_ToFloat64(js, &g, v);
|
||||
if (JS_ToFloat64(js, &g, v) < 0) {
|
||||
// If conversion fails, clear the exception and return 0
|
||||
JS_FreeValue(js, JS_GetException(js));
|
||||
return 0;
|
||||
}
|
||||
if (isnan(g)) g = 0;
|
||||
return g;
|
||||
}
|
||||
@@ -696,9 +700,9 @@ JSValue js_util_camera_globals(JSContext *js, JSValue self, int argc, JSValue *a
|
||||
JSValue camera = argv[0];
|
||||
if(JS_IsNull(camera)) return JS_NULL;
|
||||
|
||||
HMM_Vec2 size; HMM_Vec3 pos; HMM_Quat rotation;
|
||||
double fov = 0; int ortho; double near_z = 0; double far_z = 0;
|
||||
HMM_Vec2 anchor;
|
||||
HMM_Vec2 size = {0}; HMM_Vec3 pos = {0}; HMM_Quat rotation = {0,0,0,1};
|
||||
double fov = 0; int ortho = 0; double near_z = 0; double far_z = 0;
|
||||
HMM_Vec2 anchor = {0};
|
||||
|
||||
JS_GETPROP(js, size, camera, size, vec2)
|
||||
JS_GETPROP(js, fov, camera, fov, number)
|
||||
@@ -708,8 +712,6 @@ JSValue js_util_camera_globals(JSContext *js, JSValue self, int argc, JSValue *a
|
||||
JS_GETPROP(js, anchor, camera, anchor, vec2)
|
||||
JS_GETPROP(js, pos, camera, pos, vec3)
|
||||
JS_GETPROP(js, rotation, camera, rotation, quat)
|
||||
|
||||
rotation.w = 1;
|
||||
|
||||
HMM_Mat4 proj, view;
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ QJSCLASS(blob,)
|
||||
static JSValue js_blob_constructor(JSContext *ctx, JSValueConst new_target,
|
||||
int argc, JSValueConst *argv) {
|
||||
blob *bd = NULL;
|
||||
|
||||
// new Blob()
|
||||
if (argc == 0) {
|
||||
// empty antestone blob
|
||||
@@ -40,9 +39,9 @@ static JSValue js_blob_constructor(JSContext *ctx, JSValueConst new_target,
|
||||
// new Blob(length, logical/random)
|
||||
else if (argc == 2 && JS_IsNumber(argv[0])) {
|
||||
int64_t length_bits;
|
||||
if (JS_ToInt64(ctx, &length_bits, argv[0]) < 0) {
|
||||
if (JS_ToInt64(ctx, &length_bits, argv[0]) < 0)
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
if (length_bits < 0) length_bits = 0;
|
||||
|
||||
if (JS_IsBool(argv[1])) {
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
#include "jsffi.h"
|
||||
|
||||
JSC_CCALL(os_gc, JS_RunGC(JS_GetRuntime(js)) )
|
||||
JSC_CCALL(os_mem_limit, JS_SetMemoryLimit(JS_GetRuntime(js), js2number(js,argv[0])))
|
||||
JSC_CCALL(os_mem_limit,
|
||||
double val;
|
||||
JS_ToFloat64(js, &val, argv[0]);
|
||||
JS_SetMemoryLimit(JS_GetRuntime(js), val);
|
||||
)
|
||||
JSC_CCALL(os_gc_threshold, JS_SetGCThreshold(JS_GetRuntime(js), js2number(js,argv[0])))
|
||||
JSC_CCALL(os_max_stacksize, JS_SetMaxStackSize(JS_GetRuntime(js), js2number(js,argv[0])))
|
||||
|
||||
|
||||
@@ -152,7 +152,6 @@ static void nota_encode_value(NotaEncodeContext *enc, JSValueConst val, JSValueC
|
||||
nota_write_number(&enc->nb, d);
|
||||
break;
|
||||
}
|
||||
case JS_TAG_BIG_INT:
|
||||
case JS_TAG_FLOAT64: {
|
||||
const char *str = JS_ToCString(ctx, replaced);
|
||||
nota_write_number_str(&enc->nb, str);
|
||||
|
||||
@@ -1781,8 +1781,6 @@ JSC_CCALL(sdl_createWindowAndRenderer,
|
||||
#include "qjs_wota.h"
|
||||
|
||||
JSValue js_sdl_video_use(JSContext *js) {
|
||||
printf("initing on thread %d\n", SDL_GetThreadID(NULL));
|
||||
|
||||
if (!SDL_Init(SDL_INIT_VIDEO))
|
||||
return JS_ThrowInternalError(js, "Unable to initialize video subsystem: %s", SDL_GetError());
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC
|
||||
break;
|
||||
}
|
||||
case JS_TAG_FLOAT64:
|
||||
case JS_TAG_BIG_INT: {
|
||||
{
|
||||
double d;
|
||||
if (JS_ToFloat64(ctx, &d, replaced) < 0) {
|
||||
wota_write_sym(&enc->wb, WOTA_NULL);
|
||||
|
||||
@@ -221,8 +221,6 @@ DEF( gt, 1, 2, 1, none)
|
||||
DEF( gte, 1, 2, 1, none)
|
||||
DEF( instanceof, 1, 2, 1, none)
|
||||
DEF( in, 1, 2, 1, none)
|
||||
DEF( eq, 1, 2, 1, none)
|
||||
DEF( neq, 1, 2, 1, none)
|
||||
DEF( strict_eq, 1, 2, 1, none)
|
||||
DEF( strict_neq, 1, 2, 1, none)
|
||||
DEF( and, 1, 2, 1, none)
|
||||
|
||||
688
source/quickjs.c
688
source/quickjs.c
@@ -782,7 +782,7 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
|
||||
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
|
||||
int argc, JSValueConst *argv);
|
||||
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
|
||||
JSValue val, BOOL is_array_ctor);
|
||||
JSValue val);
|
||||
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
|
||||
JSValueConst val, int flags, int scope_idx);
|
||||
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
|
||||
@@ -864,7 +864,7 @@ static JSProperty *add_property(JSContext *ctx,
|
||||
JSObject *p, JSAtom prop, int prop_flags);
|
||||
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
|
||||
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
|
||||
|
||||
static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1);
|
||||
static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);
|
||||
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
|
||||
JSAtom prop, JSValueConst val,
|
||||
@@ -882,9 +882,9 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
|
||||
static int js_string_compare(JSContext *ctx,
|
||||
const JSString *p1, const JSString *p2);
|
||||
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
|
||||
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
|
||||
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
|
||||
JSValue prop, JSValue val, int flags);
|
||||
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
|
||||
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
|
||||
JSObject *p, JSAtom prop);
|
||||
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
|
||||
@@ -2546,73 +2546,6 @@ static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
|
||||
}
|
||||
}
|
||||
|
||||
/* This test must be fast if atom is not a numeric index (e.g. a
|
||||
method name). Return JS_NULL if not a numeric
|
||||
index. JS_EXCEPTION can also be returned. */
|
||||
static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
|
||||
{
|
||||
JSRuntime *rt = ctx->rt;
|
||||
JSAtomStruct *p1;
|
||||
JSString *p;
|
||||
int c, ret;
|
||||
JSValue num, str;
|
||||
|
||||
if (__JS_AtomIsTaggedInt(atom))
|
||||
return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
|
||||
assert(atom < rt->atom_size);
|
||||
p1 = rt->atom_array[atom];
|
||||
if (p1->atom_type != JS_ATOM_TYPE_STRING)
|
||||
return JS_NULL;
|
||||
switch(atom) {
|
||||
case JS_ATOM_minus_zero:
|
||||
return __JS_NewFloat64(ctx, -0.0);
|
||||
case JS_ATOM_Infinity:
|
||||
return __JS_NewFloat64(ctx, INFINITY);
|
||||
case JS_ATOM_minus_Infinity:
|
||||
return __JS_NewFloat64(ctx, -INFINITY);
|
||||
case JS_ATOM_NaN:
|
||||
return __JS_NewFloat64(ctx, NAN);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
p = p1;
|
||||
if (p->len == 0)
|
||||
return JS_NULL;
|
||||
c = string_get(p, 0);
|
||||
if (!is_num(c) && c != '-')
|
||||
return JS_NULL;
|
||||
/* this is ECMA CanonicalNumericIndexString primitive */
|
||||
num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
|
||||
if (JS_IsException(num))
|
||||
return num;
|
||||
str = JS_ToString(ctx, num);
|
||||
if (JS_IsException(str)) {
|
||||
JS_FreeValue(ctx, num);
|
||||
return str;
|
||||
}
|
||||
ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
|
||||
JS_FreeValue(ctx, str);
|
||||
if (ret == 0) {
|
||||
return num;
|
||||
} else {
|
||||
JS_FreeValue(ctx, num);
|
||||
return JS_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if exception or TRUE/FALSE */
|
||||
int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
|
||||
{
|
||||
JSValue num;
|
||||
num = JS_AtomIsNumericIndex1(ctx, atom);
|
||||
if (likely(JS_IsNull(num)))
|
||||
return FALSE;
|
||||
if (JS_IsException(num))
|
||||
return -1;
|
||||
JS_FreeValue(ctx, num);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void JS_FreeAtom(JSContext *ctx, JSAtom v)
|
||||
{
|
||||
if (!__JS_AtomIsConst(v))
|
||||
@@ -7534,8 +7467,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
|
||||
uint32_t len, idx, cur_len;
|
||||
int i, ret;
|
||||
|
||||
/* Note: this call can reallocate the properties of 'p' */
|
||||
ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
|
||||
ret = JS_ToArrayLengthFree(ctx, &len, val);
|
||||
if (ret)
|
||||
return -1;
|
||||
/* JS_ToArrayLengthFree() must be done before the read-only test */
|
||||
@@ -8258,8 +8190,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
|
||||
/* the range of the Array length property is always tested before */
|
||||
if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
|
||||
uint32_t array_length;
|
||||
if (JS_ToArrayLengthFree(ctx, &array_length,
|
||||
JS_DupValue(ctx, val), FALSE)) {
|
||||
if (JS_ToArrayLengthFree(ctx, &array_length, JS_DupValue(ctx, val))) {
|
||||
return -1;
|
||||
}
|
||||
/* this code relies on the fact that Uint32 are never allocated */
|
||||
@@ -9355,177 +9286,68 @@ done:
|
||||
goto done;
|
||||
}
|
||||
|
||||
typedef enum JSToNumberHintEnum {
|
||||
TON_FLAG_NUMBER,
|
||||
TON_FLAG_NUMERIC,
|
||||
} JSToNumberHintEnum;
|
||||
|
||||
static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
|
||||
JSToNumberHintEnum flag)
|
||||
/* Strict JS_ToNumber - only accepts numbers (int or float64), raises error otherwise */
|
||||
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
|
||||
{
|
||||
uint32_t tag;
|
||||
JSValue ret;
|
||||
|
||||
redo:
|
||||
|
||||
tag = JS_VALUE_GET_NORM_TAG(val);
|
||||
switch(tag) {
|
||||
case JS_TAG_FLOAT64:
|
||||
case JS_TAG_INT:
|
||||
case JS_TAG_EXCEPTION:
|
||||
ret = val;
|
||||
break;
|
||||
case JS_TAG_BOOL:
|
||||
case JS_TAG_NULL:
|
||||
ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
|
||||
break;
|
||||
case JS_TAG_OBJECT:
|
||||
val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
|
||||
if (JS_IsException(val))
|
||||
return JS_EXCEPTION;
|
||||
goto redo;
|
||||
case JS_TAG_STRING:
|
||||
case JS_TAG_STRING_ROPE:
|
||||
{
|
||||
const char *str;
|
||||
const char *p;
|
||||
size_t len;
|
||||
|
||||
str = JS_ToCStringLen(ctx, &len, val);
|
||||
JS_FreeValue(ctx, val);
|
||||
if (!str)
|
||||
return JS_EXCEPTION;
|
||||
p = str;
|
||||
p += skip_spaces(p);
|
||||
if ((p - str) == len) {
|
||||
ret = JS_NewInt32(ctx, 0);
|
||||
} else {
|
||||
int flags = ATOD_ACCEPT_BIN_OCT;
|
||||
ret = js_atof(ctx, p, &p, 0, flags);
|
||||
if (!JS_IsException(ret)) {
|
||||
p += skip_spaces(p);
|
||||
if ((p - str) != len) {
|
||||
JS_FreeValue(ctx, ret);
|
||||
ret = JS_NAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
break;
|
||||
case JS_TAG_SYMBOL:
|
||||
JS_FreeValue(ctx, val);
|
||||
return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
|
||||
case JS_TAG_FLOAT64:
|
||||
return JS_DupValue(ctx, val);
|
||||
default:
|
||||
JS_FreeValue(ctx, val);
|
||||
ret = JS_NAN;
|
||||
break;
|
||||
return JS_ThrowTypeError(ctx, "value is not a number");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
|
||||
{
|
||||
return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
|
||||
}
|
||||
|
||||
static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
|
||||
{
|
||||
return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
|
||||
}
|
||||
|
||||
static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
|
||||
{
|
||||
return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
|
||||
}
|
||||
|
||||
static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
|
||||
JSValue val)
|
||||
{
|
||||
double d;
|
||||
uint32_t tag;
|
||||
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val))
|
||||
goto fail;
|
||||
tag = JS_VALUE_GET_NORM_TAG(val);
|
||||
switch(tag) {
|
||||
case JS_TAG_INT:
|
||||
d = JS_VALUE_GET_INT(val);
|
||||
break;
|
||||
case JS_TAG_FLOAT64:
|
||||
d = JS_VALUE_GET_FLOAT64(val);
|
||||
break;
|
||||
return val;
|
||||
default:
|
||||
abort();
|
||||
JS_FreeValue(ctx, val);
|
||||
return JS_ThrowTypeError(ctx, "value is not a number");
|
||||
}
|
||||
*pres = d;
|
||||
return 0;
|
||||
fail:
|
||||
*pres = JS_FLOAT64_NAN;
|
||||
}
|
||||
|
||||
static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val) {
|
||||
// 1) convert and take ownership of `val`
|
||||
JSValue num = JS_ToNumberFree(ctx, val);
|
||||
// 2) did ToNumber itself throw?
|
||||
if (JS_IsException(num))
|
||||
return -1;
|
||||
|
||||
// 3) inspect the tag
|
||||
uint32_t tag = JS_VALUE_GET_TAG(num);
|
||||
if (tag == JS_TAG_INT) {
|
||||
*pres = (double)JS_VALUE_GET_INT(num);
|
||||
JS_FreeValue(ctx, num);
|
||||
return 0;
|
||||
}
|
||||
if (JS_TAG_IS_FLOAT64(tag)) {
|
||||
*pres = JS_VALUE_GET_FLOAT64(num);
|
||||
JS_FreeValue(ctx, num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 4) anything else is an error
|
||||
JS_FreeValue(ctx, num);
|
||||
JS_ThrowTypeError(ctx, "cannot convert to float64");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
|
||||
{
|
||||
uint32_t tag;
|
||||
|
||||
tag = JS_VALUE_GET_TAG(val);
|
||||
if (tag <= JS_TAG_NULL) {
|
||||
*pres = JS_VALUE_GET_INT(val);
|
||||
return 0;
|
||||
} else if (JS_TAG_IS_FLOAT64(tag)) {
|
||||
*pres = JS_VALUE_GET_FLOAT64(val);
|
||||
return 0;
|
||||
} else {
|
||||
return __JS_ToFloat64Free(ctx, pres, val);
|
||||
}
|
||||
}
|
||||
|
||||
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
|
||||
{
|
||||
return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
|
||||
}
|
||||
|
||||
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
|
||||
{
|
||||
return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
|
||||
}
|
||||
|
||||
/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
|
||||
static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
|
||||
{
|
||||
uint32_t tag;
|
||||
JSValue ret;
|
||||
|
||||
redo:
|
||||
tag = JS_VALUE_GET_NORM_TAG(val);
|
||||
switch(tag) {
|
||||
case JS_TAG_INT:
|
||||
case JS_TAG_BOOL:
|
||||
case JS_TAG_NULL:
|
||||
ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
|
||||
break;
|
||||
case JS_TAG_FLOAT64:
|
||||
{
|
||||
double d = JS_VALUE_GET_FLOAT64(val);
|
||||
if (isnan(d)) {
|
||||
ret = JS_NewInt32(ctx, 0);
|
||||
} else {
|
||||
/* convert -0 to +0 */
|
||||
d = trunc(d) + 0.0;
|
||||
ret = JS_NewFloat64(ctx, d);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val))
|
||||
return val;
|
||||
goto redo;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Note: the integer value is satured to 32 bits */
|
||||
static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
|
||||
{
|
||||
@@ -9559,12 +9381,8 @@ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val)) {
|
||||
*pres = 0;
|
||||
return -1;
|
||||
}
|
||||
goto redo;
|
||||
val = JS_ThrowTypeError(ctx, "could not coerce to integer");
|
||||
return -1;
|
||||
}
|
||||
*pres = ret;
|
||||
return 0;
|
||||
@@ -9623,12 +9441,8 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val)) {
|
||||
*pres = 0;
|
||||
return -1;
|
||||
}
|
||||
goto redo;
|
||||
val = JS_ThrowTypeError(ctx, "could not coerce to int64");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9693,13 +9507,11 @@ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val)) {
|
||||
*pres = 0;
|
||||
return -1;
|
||||
}
|
||||
goto redo;
|
||||
JS_ThrowTypeError(ctx, "could not convert to number.");
|
||||
*pres = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pres = ret;
|
||||
return 0;
|
||||
}
|
||||
@@ -9750,13 +9562,11 @@ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val)) {
|
||||
*pres = 0;
|
||||
return -1;
|
||||
}
|
||||
goto redo;
|
||||
JS_ThrowTypeError(ctx, "could not convert to number.");
|
||||
*pres = 0;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
*pres = ret;
|
||||
return 0;
|
||||
}
|
||||
@@ -9772,7 +9582,7 @@ static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
|
||||
}
|
||||
|
||||
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
|
||||
JSValue val, BOOL is_array_ctor)
|
||||
JSValue val)
|
||||
{
|
||||
uint32_t tag, len;
|
||||
|
||||
@@ -9789,48 +9599,27 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
|
||||
len = v;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (JS_TAG_IS_FLOAT64(tag)) {
|
||||
double d;
|
||||
d = JS_VALUE_GET_FLOAT64(val);
|
||||
if (!(d >= 0 && d <= UINT32_MAX))
|
||||
goto fail;
|
||||
len = (uint32_t)d;
|
||||
if (len != d)
|
||||
goto fail;
|
||||
} else {
|
||||
uint32_t len1;
|
||||
|
||||
if (is_array_ctor) {
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val))
|
||||
return -1;
|
||||
/* cannot recurse because val is a number */
|
||||
if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
|
||||
return -1;
|
||||
} else {
|
||||
/* legacy behavior: must do the conversion twice and compare */
|
||||
if (JS_ToUint32(ctx, &len, val)) {
|
||||
JS_FreeValue(ctx, val);
|
||||
return -1;
|
||||
}
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val))
|
||||
return -1;
|
||||
/* cannot recurse because val is a number */
|
||||
if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
|
||||
return -1;
|
||||
if (len1 != len) {
|
||||
fail:
|
||||
JS_ThrowRangeError(ctx, "invalid array length");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
case JS_TAG_FLOAT64:
|
||||
{
|
||||
double d;
|
||||
d = JS_VALUE_GET_FLOAT64(val);
|
||||
if (!(d >= 0 && d <= UINT32_MAX))
|
||||
goto fail;
|
||||
len = (uint32_t)d;
|
||||
if (len != d)
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*plen = 0;
|
||||
return -1;
|
||||
}
|
||||
*plen = len;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
*plen = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
|
||||
@@ -10714,42 +10503,7 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
|
||||
|
||||
op1 = sp[-1];
|
||||
/* fast path for float64 */
|
||||
if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
|
||||
goto handle_float64;
|
||||
op1 = JS_ToNumericFree(ctx, op1);
|
||||
if (JS_IsException(op1))
|
||||
goto exception;
|
||||
tag = JS_VALUE_GET_TAG(op1);
|
||||
switch(tag) {
|
||||
case JS_TAG_INT:
|
||||
{
|
||||
int64_t v64;
|
||||
v64 = JS_VALUE_GET_INT(op1);
|
||||
switch(op) {
|
||||
case OP_inc:
|
||||
case OP_dec:
|
||||
v = 2 * (op - OP_dec) - 1;
|
||||
v64 += v;
|
||||
break;
|
||||
case OP_plus:
|
||||
break;
|
||||
case OP_neg:
|
||||
if (v64 == 0) {
|
||||
sp[-1] = __JS_NewFloat64(ctx, -0.0);
|
||||
return 0;
|
||||
} else {
|
||||
v64 = -v64;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
sp[-1] = JS_NewInt64(ctx, v64);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
handle_float64:
|
||||
{
|
||||
if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) {
|
||||
double d;
|
||||
d = JS_VALUE_GET_FLOAT64(op1);
|
||||
switch(op) {
|
||||
@@ -10767,11 +10521,9 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
|
||||
abort();
|
||||
}
|
||||
sp[-1] = __JS_NewFloat64(ctx, d);
|
||||
}
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
exception:
|
||||
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
}
|
||||
@@ -10783,40 +10535,22 @@ static __exception int js_post_inc_slow(JSContext *ctx,
|
||||
|
||||
/* XXX: allow custom operators */
|
||||
op1 = sp[-1];
|
||||
op1 = JS_ToNumericFree(ctx, op1);
|
||||
if (JS_IsException(op1)) {
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
if (!JS_IsNumber(op1)) {
|
||||
JS_ThrowTypeError(ctx, "operator only works on numbers");
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
}
|
||||
sp[-1] = op1;
|
||||
sp[0] = JS_DupValue(ctx, op1);
|
||||
return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
|
||||
}
|
||||
|
||||
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
|
||||
{
|
||||
JSValue op1;
|
||||
|
||||
op1 = sp[-1];
|
||||
op1 = JS_ToNumericFree(ctx, op1);
|
||||
if (JS_IsException(op1))
|
||||
goto exception;
|
||||
int32_t v1;
|
||||
if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
|
||||
goto exception;
|
||||
sp[-1] = JS_NewInt32(ctx, ~v1);
|
||||
return 0;
|
||||
exception:
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
|
||||
OPCodeEnum op)
|
||||
{
|
||||
JSValue op1, op2;
|
||||
uint32_t tag1, tag2;
|
||||
double d1, d2;
|
||||
double d1, d2, dr;
|
||||
|
||||
op1 = sp[-2];
|
||||
op2 = sp[-1];
|
||||
@@ -10841,62 +10575,8 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
|
||||
goto handle_float64;
|
||||
}
|
||||
|
||||
op1 = JS_ToNumericFree(ctx, op1);
|
||||
if (JS_IsException(op1)) {
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
}
|
||||
op2 = JS_ToNumericFree(ctx, op2);
|
||||
if (JS_IsException(op2)) {
|
||||
JS_FreeValue(ctx, op1);
|
||||
goto exception;
|
||||
}
|
||||
tag1 = JS_VALUE_GET_NORM_TAG(op1);
|
||||
tag2 = JS_VALUE_GET_NORM_TAG(op2);
|
||||
|
||||
if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
|
||||
int32_t v1, v2;
|
||||
int64_t v;
|
||||
v1 = JS_VALUE_GET_INT(op1);
|
||||
v2 = JS_VALUE_GET_INT(op2);
|
||||
switch(op) {
|
||||
case OP_sub:
|
||||
v = (int64_t)v1 - (int64_t)v2;
|
||||
break;
|
||||
case OP_mul:
|
||||
v = (int64_t)v1 * (int64_t)v2;
|
||||
if (v == 0 && (v1 | v2) < 0) {
|
||||
sp[-2] = __JS_NewFloat64(ctx, -0.0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case OP_div:
|
||||
sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
|
||||
return 0;
|
||||
case OP_mod:
|
||||
if (v1 < 0 || v2 <= 0) {
|
||||
sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
|
||||
return 0;
|
||||
} else {
|
||||
v = (int64_t)v1 % (int64_t)v2;
|
||||
}
|
||||
break;
|
||||
case OP_pow:
|
||||
sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
sp[-2] = JS_NewInt64(ctx, v);
|
||||
} else {
|
||||
double dr;
|
||||
/* float64 result */
|
||||
if (JS_ToFloat64Free(ctx, &d1, op1)) {
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
}
|
||||
if (JS_ToFloat64Free(ctx, &d2, op2))
|
||||
goto exception;
|
||||
goto exception;
|
||||
|
||||
handle_float64:
|
||||
switch(op) {
|
||||
case OP_sub:
|
||||
@@ -10917,9 +10597,10 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
sp[-2] = __JS_NewFloat64(ctx, dr);
|
||||
}
|
||||
sp[-2] = __JS_NewFloat64(ctx, dr);
|
||||
|
||||
return 0;
|
||||
|
||||
exception:
|
||||
sp[-2] = JS_NULL;
|
||||
sp[-1] = JS_NULL;
|
||||
@@ -10974,11 +10655,35 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
|
||||
|
||||
/* anything else → TypeError */
|
||||
} else {
|
||||
/* Get type names */
|
||||
JSAtom type1_atom = js_operator_typeof(ctx, op1);
|
||||
JSAtom type2_atom = js_operator_typeof(ctx, op2);
|
||||
const char *type1_name = JS_AtomToCString(ctx, type1_atom);
|
||||
const char *type2_name = JS_AtomToCString(ctx, type2_atom);
|
||||
|
||||
/* Convert values to strings for display */
|
||||
const char *val1_str = JS_ToCString(ctx, op1);
|
||||
const char *val2_str = JS_ToCString(ctx, op2);
|
||||
|
||||
/* Create detailed error message */
|
||||
JS_ThrowTypeError(ctx,
|
||||
"Relational operators only supported on two strings or two numbers");
|
||||
"TypeError: cannot compare \"%s\" (%s) with \"%s\" (%s)",
|
||||
val1_str ? val1_str : "(conversion failed)",
|
||||
type1_name ? type1_name : "unknown",
|
||||
val2_str ? val2_str : "(conversion failed)",
|
||||
type2_name ? type2_name : "unknown");
|
||||
|
||||
/* Free the C strings */
|
||||
if (val1_str) JS_FreeCString(ctx, val1_str);
|
||||
if (val2_str) JS_FreeCString(ctx, val2_str);
|
||||
JS_FreeCString(ctx, type1_name);
|
||||
JS_FreeCString(ctx, type2_name);
|
||||
|
||||
JS_FreeValue(ctx, op1);
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
sp[-2] = JS_NULL;
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* free the two input values and push the result */
|
||||
@@ -10986,105 +10691,6 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
|
||||
JS_FreeValue(ctx, op2);
|
||||
sp[-2] = JS_NewBool(ctx, res);
|
||||
return 0;
|
||||
|
||||
exception:
|
||||
sp[-2] = JS_NULL;
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static BOOL tag_is_number(uint32_t tag)
|
||||
{
|
||||
return (tag == JS_TAG_INT ||
|
||||
tag == JS_TAG_FLOAT64);
|
||||
}
|
||||
|
||||
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
|
||||
BOOL is_neq)
|
||||
{
|
||||
JSValue op1, op2;
|
||||
int res;
|
||||
uint32_t tag1, tag2;
|
||||
|
||||
op1 = sp[-2];
|
||||
op2 = sp[-1];
|
||||
redo:
|
||||
tag1 = JS_VALUE_GET_NORM_TAG(op1);
|
||||
tag2 = JS_VALUE_GET_NORM_TAG(op2);
|
||||
if (tag_is_number(tag1) && tag_is_number(tag2)) {
|
||||
if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
|
||||
res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
|
||||
} else if ((tag1 == JS_TAG_FLOAT64 &&
|
||||
(tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
|
||||
(tag2 == JS_TAG_FLOAT64 &&
|
||||
(tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
|
||||
double d1, d2;
|
||||
if (tag1 == JS_TAG_FLOAT64) {
|
||||
d1 = JS_VALUE_GET_FLOAT64(op1);
|
||||
} else {
|
||||
d1 = JS_VALUE_GET_INT(op1);
|
||||
}
|
||||
if (tag2 == JS_TAG_FLOAT64) {
|
||||
d2 = JS_VALUE_GET_FLOAT64(op2);
|
||||
} else {
|
||||
d2 = JS_VALUE_GET_INT(op2);
|
||||
}
|
||||
res = (d1 == d2);
|
||||
}
|
||||
} else if (tag1 == tag2) {
|
||||
res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
|
||||
} else if (tag1 == JS_TAG_NULL && tag2 == JS_TAG_NULL) {
|
||||
res = TRUE;
|
||||
} else if (tag_is_string(tag1) && tag_is_string(tag2)) {
|
||||
/* needed when comparing strings and ropes */
|
||||
res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
|
||||
} else if ((tag_is_string(tag1) && tag_is_number(tag2)) ||
|
||||
(tag_is_string(tag2) && tag_is_number(tag1))) {
|
||||
|
||||
op1 = JS_ToNumericFree(ctx, op1);
|
||||
if (JS_IsException(op1)) {
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
}
|
||||
op2 = JS_ToNumericFree(ctx, op2);
|
||||
if (JS_IsException(op2)) {
|
||||
JS_FreeValue(ctx, op1);
|
||||
goto exception;
|
||||
}
|
||||
res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
|
||||
} else if (tag1 == JS_TAG_BOOL) {
|
||||
op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
|
||||
goto redo;
|
||||
} else if (tag2 == JS_TAG_BOOL) {
|
||||
op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
|
||||
goto redo;
|
||||
} else if ((tag1 == JS_TAG_OBJECT &&
|
||||
(tag_is_number(tag2) || tag_is_string(tag2) || tag2 == JS_TAG_SYMBOL)) ||
|
||||
(tag2 == JS_TAG_OBJECT &&
|
||||
(tag_is_number(tag1) || tag_is_string(tag1) || tag1 == JS_TAG_SYMBOL))) {
|
||||
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
|
||||
if (JS_IsException(op1)) {
|
||||
JS_FreeValue(ctx, op2);
|
||||
goto exception;
|
||||
}
|
||||
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
|
||||
if (JS_IsException(op2)) {
|
||||
JS_FreeValue(ctx, op1);
|
||||
goto exception;
|
||||
}
|
||||
goto redo;
|
||||
} else {
|
||||
res = FALSE;
|
||||
JS_FreeValue(ctx, op1);
|
||||
JS_FreeValue(ctx, op2);
|
||||
}
|
||||
done:
|
||||
sp[-2] = JS_NewBool(ctx, res ^ is_neq);
|
||||
return 0;
|
||||
exception:
|
||||
sp[-2] = JS_NULL;
|
||||
sp[-1] = JS_NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX: Should take JSValueConst arguments */
|
||||
@@ -14469,9 +14075,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
|
||||
sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
|
||||
} else {
|
||||
sf->cur_pc = pc;
|
||||
if (js_not_slow(ctx, sp))
|
||||
goto exception;
|
||||
sp[-1] = JS_NULL;
|
||||
}
|
||||
}
|
||||
BREAK;
|
||||
@@ -14603,8 +14207,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
|
||||
OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
|
||||
OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
|
||||
OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
|
||||
OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
|
||||
OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
|
||||
OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
|
||||
|
||||
@@ -24252,9 +23854,9 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
|
||||
case OP_typeof:
|
||||
if (OPTIMIZE) {
|
||||
/* simplify typeof tests */
|
||||
if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
|
||||
if (code_match(&cc, pos_next, OP_push_atom_value, M2(OP_strict_eq, OP_strict_neq), -1)) {
|
||||
if (cc.line_num >= 0) line_num = cc.line_num;
|
||||
int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
|
||||
int op1 = cc.op;
|
||||
int op2 = -1;
|
||||
switch (cc.atom) {
|
||||
case JS_ATOM_null:
|
||||
@@ -29220,7 +28822,7 @@ static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
|
||||
return obj;
|
||||
if (argc == 1 && JS_IsNumber(argv[0])) {
|
||||
uint32_t len;
|
||||
if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
|
||||
if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
|
||||
goto fail;
|
||||
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
|
||||
goto fail;
|
||||
@@ -31120,10 +30722,49 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
|
||||
if (argc == 0) {
|
||||
val = JS_NewInt32(ctx, 0);
|
||||
} else {
|
||||
val = JS_ToNumeric(ctx, argv[0]);
|
||||
if (JS_IsException(val))
|
||||
return val;
|
||||
uint32_t tag = JS_VALUE_GET_NORM_TAG(argv[0]);
|
||||
switch(tag) {
|
||||
case JS_TAG_FLOAT64:
|
||||
case JS_TAG_INT:
|
||||
val = argv[0];
|
||||
break;
|
||||
case JS_TAG_BOOL:
|
||||
val = JS_NewInt32(ctx, JS_VALUE_GET_INT(argv[0]));
|
||||
break;
|
||||
case JS_TAG_STRING:
|
||||
case JS_TAG_STRING_ROPE:
|
||||
{
|
||||
const char *str;
|
||||
const char *p;
|
||||
size_t len;
|
||||
|
||||
str = JS_ToCStringLen(ctx, &len, val);
|
||||
JS_FreeValue(ctx, val);
|
||||
if (!str)
|
||||
return JS_EXCEPTION;
|
||||
p = str;
|
||||
p += skip_spaces(p);
|
||||
if ((p - str) == len) {
|
||||
val = JS_NewInt32(ctx, 0);
|
||||
} else {
|
||||
int flags = ATOD_ACCEPT_BIN_OCT;
|
||||
val = js_atof(ctx, p, &p, 0, flags);
|
||||
if (!JS_IsException(val)) {
|
||||
p += skip_spaces(p);
|
||||
if ((p - str) != len) {
|
||||
JS_FreeValue(ctx, val);
|
||||
val = JS_NAN;
|
||||
}
|
||||
}
|
||||
}
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
val = JS_ThrowTypeError(ctx, "cannot convert to a number");
|
||||
}
|
||||
}
|
||||
|
||||
if (!JS_IsNull(new_target)) {
|
||||
obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
|
||||
if (!JS_IsException(obj))
|
||||
@@ -32648,12 +32289,6 @@ static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
return JS_ToQuotedString(ctx, this_val);
|
||||
}
|
||||
|
||||
/* return 0 if before the first char */
|
||||
static int string_prevc(JSString *p, int *pidx)
|
||||
{
|
||||
@@ -33041,7 +32676,6 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = {
|
||||
JS_ALIAS_DEF("trimLeft", "trimStart" ),
|
||||
JS_CFUNC_DEF("toString", 0, js_string_toString ),
|
||||
JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
|
||||
JS_CFUNC_DEF("__quote", 1, js_string___quote ),
|
||||
JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
|
||||
JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
|
||||
JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
|
||||
@@ -35242,9 +34876,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
|
||||
goto exception;
|
||||
goto concat_primitive;
|
||||
} else if (cl == JS_CLASS_NUMBER) {
|
||||
val = JS_ToNumberFree(ctx, val);
|
||||
if (JS_IsException(val))
|
||||
goto exception;
|
||||
set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
|
||||
goto concat_primitive;
|
||||
} else if (cl == JS_CLASS_BOOLEAN)
|
||||
{
|
||||
@@ -35471,18 +35103,6 @@ JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
|
||||
}
|
||||
}
|
||||
space = JS_DupValue(ctx, space0);
|
||||
if (JS_IsObject(space)) {
|
||||
JSObject *p = JS_VALUE_GET_OBJ(space);
|
||||
if (p->class_id == JS_CLASS_NUMBER) {
|
||||
space = JS_ToNumberFree(ctx, space);
|
||||
} else if (p->class_id == JS_CLASS_STRING) {
|
||||
space = JS_ToStringFree(ctx, space);
|
||||
}
|
||||
if (JS_IsException(space)) {
|
||||
JS_FreeValue(ctx, space);
|
||||
goto exception;
|
||||
}
|
||||
}
|
||||
if (JS_IsNumber(space)) {
|
||||
int n;
|
||||
if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
|
||||
|
||||
@@ -70,12 +70,9 @@ typedef uint32_t JSAtom;
|
||||
#define JS_LIMB_BITS 32
|
||||
#endif
|
||||
|
||||
#define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS
|
||||
|
||||
enum {
|
||||
/* all tags with a reference count are negative */
|
||||
JS_TAG_FIRST = -9, /* first negative tag */
|
||||
JS_TAG_BIG_INT = -9,
|
||||
JS_TAG_SYMBOL = -8,
|
||||
JS_TAG_STRING = -7,
|
||||
JS_TAG_STRING_ROPE = -6,
|
||||
@@ -86,11 +83,9 @@ enum {
|
||||
JS_TAG_INT = 0,
|
||||
JS_TAG_BOOL = 1,
|
||||
JS_TAG_NULL = 2,
|
||||
// TAG_UNDEFINED
|
||||
JS_TAG_UNINITIALIZED = 4,
|
||||
JS_TAG_CATCH_OFFSET = 5,
|
||||
JS_TAG_EXCEPTION = 6,
|
||||
JS_TAG_SHORT_BIG_INT = 7,
|
||||
JS_TAG_FLOAT64 = 8,
|
||||
/* any larger tag is FLOAT64 if JS_NAN_BOXING */
|
||||
};
|
||||
@@ -116,7 +111,6 @@ typedef const struct __JSValue *JSValueConst;
|
||||
#define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4)
|
||||
#define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v)
|
||||
#define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v)
|
||||
#define JS_VALUE_GET_SHORT_BIG_INT(v) JS_VALUE_GET_INT(v)
|
||||
#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf)
|
||||
|
||||
#define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag))
|
||||
@@ -145,7 +139,6 @@ typedef uint64_t JSValue;
|
||||
#define JS_VALUE_GET_TAG(v) (int)((v) >> 32)
|
||||
#define JS_VALUE_GET_INT(v) (int)(v)
|
||||
#define JS_VALUE_GET_BOOL(v) (int)(v)
|
||||
#define JS_VALUE_GET_SHORT_BIG_INT(v) (int)(v)
|
||||
#define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v)
|
||||
|
||||
#define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val))
|
||||
@@ -208,11 +201,6 @@ typedef union JSValueUnion {
|
||||
int32_t int32;
|
||||
double float64;
|
||||
void *ptr;
|
||||
#if JS_SHORT_BIG_INT_BITS == 32
|
||||
int32_t short_big_int;
|
||||
#else
|
||||
int64_t short_big_int;
|
||||
#endif
|
||||
} JSValueUnion;
|
||||
|
||||
typedef struct JSValue {
|
||||
@@ -228,7 +216,6 @@ typedef struct JSValue {
|
||||
#define JS_VALUE_GET_INT(v) ((v).u.int32)
|
||||
#define JS_VALUE_GET_BOOL(v) ((v).u.int32)
|
||||
#define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
|
||||
#define JS_VALUE_GET_SHORT_BIG_INT(v) ((v).u.short_big_int)
|
||||
#define JS_VALUE_GET_PTR(v) ((v).u.ptr)
|
||||
|
||||
#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
|
||||
@@ -682,7 +669,7 @@ static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
|
||||
{
|
||||
return JS_ToInt32(ctx, (int32_t*)pres, val);
|
||||
}
|
||||
int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom);
|
||||
|
||||
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
|
||||
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);
|
||||
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val);
|
||||
|
||||
Reference in New Issue
Block a user