visaljs 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_LICENSES +1 -1
- package/cli.js +2732 -771
- package/node/include/js_node.h +1 -0
- package/node/prelude/http.js +11 -9
- package/node/prelude/internal/http_chars.ts +22 -0
- package/node/prelude/net.js +18 -14
- package/node/src/host_sys.c +9 -0
- package/package.json +1 -1
- package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
- package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
- package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
- package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
- package/runtime/include/js_buffer.h +185 -0
- package/runtime/include/js_builtins.h +53 -0
- package/runtime/include/js_exception.h +3 -0
- package/runtime/include/js_function.h +1 -1
- package/runtime/include/js_object.h +21 -3
- package/runtime/include/js_ops.h +27 -0
- package/runtime/include/js_runtime.h +1 -0
- package/runtime/include/js_web.h +0 -3
- package/runtime/include/jscontext.h +7 -0
- package/runtime/src/builtins.c +17 -4
- package/runtime/src/function.c +37 -10
- package/runtime/src/gc.c +3 -1
- package/runtime/src/iterator.c +5 -1
- package/runtime/src/object.c +42 -6
- package/runtime/src/typedarray.c +23 -0
|
@@ -226,6 +226,12 @@ struct JSRuntime {
|
|
|
226
226
|
const JSBigIntOps *bigint; /* set by the bigint component */
|
|
227
227
|
/* A typed array's length now: -1 when out of bounds (detached), -2 for anything else. */
|
|
228
228
|
double (*typed_array_length)(JSValue v);
|
|
229
|
+
/* Set by typed arrays: obj[i] and obj[i] = d (a Number) of a typed array, inline, for an index
|
|
230
|
+
* in bounds and an element that is a Number (not a BigInt): true when done; false for
|
|
231
|
+
* anything else, which takes the generic path. */
|
|
232
|
+
bool (*typed_array_get)(JSValue v, int32_t i, JSValue *out);
|
|
233
|
+
bool (*typed_array_set)(JSValue v, int32_t i, double d);
|
|
234
|
+
const struct JSClass *typed_array_class; /* set by typed arrays: js_buffer.h's inline element access tests it */
|
|
229
235
|
/* Set by typed arrays: a typed array's or DataView's bytes (its current window), true; false
|
|
230
236
|
* for anything else (an ArrayBuffer too: process.stdout.write takes views only). */
|
|
231
237
|
bool (*view_bytes)(JSValue v, uint8_t **data, size_t *length);
|
|
@@ -240,6 +246,7 @@ struct JSContext {
|
|
|
240
246
|
uint8_t barrier_threshold; /* js_store's slow path runs for an owner whose GC byte is this or more */
|
|
241
247
|
JSValue intrinsics[JS_INTRINSIC_COUNT];
|
|
242
248
|
JSContext *next_realm;
|
|
249
|
+
struct JSShape *array_shape; /* the root shape of its arrays with Array.prototype (js_new_array), made at the first */
|
|
243
250
|
};
|
|
244
251
|
|
|
245
252
|
JSRuntime *js_runtime_new(void);
|
package/runtime/src/builtins.c
CHANGED
|
@@ -793,7 +793,7 @@ CORE(object_proto_lookup_setter) {
|
|
|
793
793
|
|
|
794
794
|
/* ---- Function.prototype (§20.2.3) --------------------------------------------------------------- */
|
|
795
795
|
|
|
796
|
-
|
|
796
|
+
JSValue js_function_proto_call(JSContext *ctx, JSValue callee, JSValue this_val, uint32_t argc, const JSValue *argv, JSValue new_target) {
|
|
797
797
|
UNUSED_ARGS;
|
|
798
798
|
if (!js_is_callable(this_val)) return js_throw_type_error(ctx, "Function.prototype.call called on a non-function");
|
|
799
799
|
return js_call(ctx, this_val, ARG(0), argc > 1 ? argc - 1 : 0, argv + (argc > 1 ? 1 : argc));
|
|
@@ -822,10 +822,23 @@ static JSValueArray *list_from_array_like(JSContext *ctx, JSValue v) {
|
|
|
822
822
|
|
|
823
823
|
JSValueArray *js_list_from_array_like(JSContext *ctx, JSValue v) { return list_from_array_like(ctx, v); }
|
|
824
824
|
|
|
825
|
-
|
|
825
|
+
JSValue js_function_proto_apply(JSContext *ctx, JSValue callee, JSValue this_val, uint32_t argc, const JSValue *argv, JSValue new_target) {
|
|
826
826
|
UNUSED_ARGS;
|
|
827
827
|
if (!js_is_callable(this_val)) return js_throw_type_error(ctx, "Function.prototype.apply was called on a non-function");
|
|
828
828
|
if (js_is_nullish(ARG(1))) return js_call(ctx, this_val, ARG(0), 0, NULL);
|
|
829
|
+
/* a short dense array without holes (emit's arguments): its elements are its own data
|
|
830
|
+
* properties, so reading them can't run code. Copied, as the callee may change the array. */
|
|
831
|
+
if (js_is_array(ARG(1))) {
|
|
832
|
+
JSObject *a = js_as_object(ARG(1));
|
|
833
|
+
JSElements *e = a->elements;
|
|
834
|
+
uint32_t n = js_array_length(a);
|
|
835
|
+
JSValue args[8];
|
|
836
|
+
if (e->kind == JS_ELEMENTS_DENSE && e->length == n && n <= 8) {
|
|
837
|
+
uint32_t i = 0;
|
|
838
|
+
while (i < n && !js_is_empty(e->data[i])) args[i] = e->data[i], i++;
|
|
839
|
+
if (i == n) return js_call(ctx, this_val, ARG(0), n, args);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
829
842
|
JSValueArray *list = list_from_array_like(ctx, ARG(1));
|
|
830
843
|
if (!list) return JS_EXCEPTION;
|
|
831
844
|
JSValue r = js_call(ctx, this_val, ARG(0), list->cell.aux, list->values);
|
|
@@ -959,8 +972,8 @@ void js_builtins_realm_init(JSContext *ctx, JSObject *global) {
|
|
|
959
972
|
|
|
960
973
|
JSValue object = define_constructor(ctx, global, "Object", object_ctor, 1, in[JS_INTRINSIC_OBJECT_PROTOTYPE]);
|
|
961
974
|
static const JSBuiltin function_proto[] = {
|
|
962
|
-
JS_BUILTIN_FN("call",
|
|
963
|
-
JS_BUILTIN_FN("apply",
|
|
975
|
+
JS_BUILTIN_FN("call", js_function_proto_call, 1),
|
|
976
|
+
JS_BUILTIN_FN("apply", js_function_proto_apply, 2),
|
|
964
977
|
JS_BUILTIN_FN("bind", function_proto_bind, 1),
|
|
965
978
|
JS_BUILTIN_FN("toString", function_proto_to_string, 0),
|
|
966
979
|
};
|
package/runtime/src/function.c
CHANGED
|
@@ -222,10 +222,38 @@ JSValue js_get_prototype_from_constructor(JSContext *ctx, JSValue new_target, JS
|
|
|
222
222
|
return realm ? realm->intrinsics[fallback] : JS_EXCEPTION;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
/* The root shape of the objects `new f` makes, with at least `slots` inline slots: kept on f, and
|
|
226
|
+
* grown by learn_instance_slots to what its instances end up holding. */
|
|
227
|
+
static JSShape *instance_root(JSContext *ctx, JSFunction *f, JSValue proto, uint16_t slots) {
|
|
228
|
+
JSShape *s = f->instance_shape;
|
|
229
|
+
if (JS_UNLIKELY(!s || !js_same_bits(s->proto, proto) || s->inline_cap < slots)) {
|
|
230
|
+
s = js_shape_root(ctx, &js_class_object, proto, slots);
|
|
231
|
+
js_store_ptr(ctx, &f->obj.cell, &f->instance_shape, s);
|
|
232
|
+
}
|
|
233
|
+
return s;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Slack tracking: when the constructors (a class's and its bases') left `v` with more properties
|
|
237
|
+
* than its root shape has inline slots, the next instances get room for them all. A derived
|
|
238
|
+
* class's `this` is made by its base, which can't count its subclasses' properties; the rest
|
|
239
|
+
* would sit out of line, where an inline cache's hit isn't inlined. */
|
|
240
|
+
static void learn_instance_slots(JSContext *ctx, JSFunction *f, JSValue v) {
|
|
241
|
+
JSShape *root = f->instance_shape;
|
|
242
|
+
if (!root || !js_is_object(v)) return;
|
|
243
|
+
JSShape *s = js_as_object(v)->shape;
|
|
244
|
+
if (JS_LIKELY(s->prop_count <= root->inline_cap || root->inline_cap >= JS_MAX_INLINE_SLOTS)) return;
|
|
245
|
+
JSShape *r = s;
|
|
246
|
+
while (r->parent) r = r->parent;
|
|
247
|
+
if (r != root) return; /* not made from it: an object the constructor returned, or a dictionary */
|
|
248
|
+
JSShape *grown = js_shape_root(ctx, &js_class_object, root->proto, (uint16_t)(s->prop_count < JS_MAX_INLINE_SLOTS ? s->prop_count : JS_MAX_INLINE_SLOTS));
|
|
249
|
+
js_store_ptr(ctx, &f->obj.cell, &f->instance_shape, grown);
|
|
250
|
+
}
|
|
251
|
+
|
|
225
252
|
JSValue js_create_from_constructor(JSContext *ctx, JSValue new_target, JSIntrinsic fallback) {
|
|
226
253
|
JSValue proto = js_get_prototype_from_constructor(ctx, new_target, fallback);
|
|
227
254
|
if (js_is_exception(proto)) return JS_EXCEPTION;
|
|
228
|
-
return js_new_object_proto(ctx, proto, JS_DEFAULT_INLINE_SLOTS);
|
|
255
|
+
if (!js_is_function(new_target)) return js_new_object_proto(ctx, proto, JS_DEFAULT_INLINE_SLOTS);
|
|
256
|
+
return js_object_value(js_alloc_object(ctx, JS_CELL_OBJECT, instance_root(ctx, js_as_function(new_target), proto, JS_DEFAULT_INLINE_SLOTS)));
|
|
229
257
|
}
|
|
230
258
|
|
|
231
259
|
JSValue js_new_instance(JSContext *ctx, JSValue fv, uint16_t slots, JSPropCache *ic) {
|
|
@@ -234,26 +262,25 @@ JSValue js_new_instance(JSContext *ctx, JSValue fv, uint16_t slots, JSPropCache
|
|
|
234
262
|
: js_get_prop(ctx, fv, JS_ATOM(prototype), ic);
|
|
235
263
|
if (js_is_exception(proto)) return JS_EXCEPTION;
|
|
236
264
|
if (!js_is_object(proto)) proto = ctx->intrinsics[JS_INTRINSIC_OBJECT_PROTOTYPE]; /* OrdinaryCreateFromConstructor's fallback */
|
|
237
|
-
|
|
238
|
-
JSShape *s = f->instance_shape;
|
|
239
|
-
if (JS_UNLIKELY(!s || !js_same_bits(s->proto, proto) || s->inline_cap != slots)) {
|
|
240
|
-
s = js_shape_root(ctx, &js_class_object, proto, slots);
|
|
241
|
-
js_store_ptr(ctx, &f->obj.cell, &f->instance_shape, s);
|
|
242
|
-
}
|
|
243
|
-
return js_object_value(js_alloc_object(ctx, JS_CELL_OBJECT, s));
|
|
265
|
+
return js_object_value(js_alloc_object(ctx, JS_CELL_OBJECT, instance_root(ctx, js_as_function(fv), proto, slots)));
|
|
244
266
|
}
|
|
245
267
|
|
|
246
268
|
JSValue js_construct(JSContext *ctx, JSValue f, uint32_t argc, const JSValue *argv, JSValue new_target, const char *callee_text) {
|
|
247
269
|
if (JS_UNLIKELY(!js_is_constructor(f))) return not_callable(ctx, f, callee_text, "constructor");
|
|
248
270
|
JSFunction *fn = js_as_function(f);
|
|
271
|
+
bool outermost = js_is_undefined(new_target) || js_same_bits(new_target, f); /* not a super() */
|
|
249
272
|
if (js_is_undefined(new_target)) new_target = f;
|
|
250
|
-
if (!(fn->flags & JS_FN_ORDINARY)) /* builtins create their own object; a derived constructor gets it from super() */
|
|
251
|
-
|
|
273
|
+
if (!(fn->flags & JS_FN_ORDINARY)) { /* builtins create their own object; a derived constructor gets it from super() */
|
|
274
|
+
JSValue r = fn->entry(fn->flags & JS_FN_PROXY ? ctx : fn->realm, f, JS_UNDEFINED, argc, argv, new_target);
|
|
275
|
+
if (outermost && (fn->flags & JS_FN_DERIVED) && !js_is_exception(r)) learn_instance_slots(ctx, fn, r);
|
|
276
|
+
return r;
|
|
277
|
+
}
|
|
252
278
|
/* [[Construct]] of an ordinary function (§10.2.2): this = a new object; an object result wins */
|
|
253
279
|
JSValue this_val = js_create_from_constructor(fn->realm, new_target, JS_INTRINSIC_OBJECT_PROTOTYPE);
|
|
254
280
|
if (js_is_exception(this_val)) return JS_EXCEPTION;
|
|
255
281
|
JSValue r = fn->entry(fn->realm, f, this_val, argc, argv, new_target);
|
|
256
282
|
if (js_is_exception(r)) return JS_EXCEPTION;
|
|
283
|
+
if (outermost) learn_instance_slots(ctx, fn, this_val);
|
|
257
284
|
return js_is_object(r) ? r : this_val;
|
|
258
285
|
}
|
|
259
286
|
|
package/runtime/src/gc.c
CHANGED
|
@@ -1646,8 +1646,10 @@ static void mark_roots(JSRuntime *rt, JSTracer *trc) {
|
|
|
1646
1646
|
js_trace_value(trc, rt->async_context);
|
|
1647
1647
|
js_jobs_trace(rt, trc); /* queued jobs, unhandled rejections */
|
|
1648
1648
|
js_weak_trace_roots(rt, trc); /* the WeakRef kept-alive set */
|
|
1649
|
-
for (JSContext *realm = rt->realms; realm; realm = realm->next_realm)
|
|
1649
|
+
for (JSContext *realm = rt->realms; realm; realm = realm->next_realm) {
|
|
1650
1650
|
for (unsigned i = 0; i < JS_INTRINSIC_COUNT; i++) js_trace_value(trc, realm->intrinsics[i]);
|
|
1651
|
+
if (realm->array_shape) js_trace_cell(trc, &realm->array_shape->cell);
|
|
1652
|
+
}
|
|
1651
1653
|
for (size_t t = 0; t < h->root_table_count; t++)
|
|
1652
1654
|
for (size_t i = 0; i < h->root_tables[t].n; i++) js_trace_value(trc, h->root_tables[t].slots[i]);
|
|
1653
1655
|
for (size_t i = 0; i < h->root_count; i++) js_trace_value(trc, *h->roots[i]);
|
package/runtime/src/iterator.c
CHANGED
|
@@ -236,7 +236,11 @@ JSValue js_iter_next(JSContext *ctx, JSValue rec) {
|
|
|
236
236
|
if (r->done) return JS_EMPTY;
|
|
237
237
|
JSValue value;
|
|
238
238
|
if (r->mode == MODE_ARRAY) {
|
|
239
|
-
|
|
239
|
+
/* a dense array's present element: what array_step's [[Get]] would read */
|
|
240
|
+
const JSElements *d = js_as_object(r->iterator)->elements;
|
|
241
|
+
uint32_t i = (uint32_t)r->index;
|
|
242
|
+
if (JS_LIKELY(d->kind == JS_ELEMENTS_DENSE && r->index < d->length && !js_is_empty(d->data[i]))) value = d->data[i];
|
|
243
|
+
else value = array_step(ctx, r->iterator, r->index, KIND_VALUES);
|
|
240
244
|
r->index++;
|
|
241
245
|
} else if (r->mode == MODE_STRING) {
|
|
242
246
|
uint32_t i = (uint32_t)r->index;
|
package/runtime/src/object.c
CHANGED
|
@@ -697,8 +697,7 @@ const JSClass js_class_array = {
|
|
|
697
697
|
"Array", sizeof(JSObject), array_get_own, array_define, array_delete, array_extra_keys, NULL, NULL, NULL,
|
|
698
698
|
};
|
|
699
699
|
|
|
700
|
-
static JSValue
|
|
701
|
-
JSShape *shape = js_shape_root(ctx, &js_class_array, proto, 0); /* named properties on arrays are rare */
|
|
700
|
+
static JSValue array_of_shape(JSContext *ctx, JSShape *shape, uint32_t capacity) {
|
|
702
701
|
JSObject *a = js_alloc_object(ctx, JS_CELL_ARRAY, shape);
|
|
703
702
|
if (capacity) {
|
|
704
703
|
JSElements *e = (JSElements *)js_alloc_cell(ctx, JS_CELL_ELEMENTS, sizeof(JSElements) + (size_t)capacity * sizeof(JSValue));
|
|
@@ -709,8 +708,13 @@ static JSValue array_with_proto(JSContext *ctx, JSValue proto, uint32_t capacity
|
|
|
709
708
|
return js_object_value(a);
|
|
710
709
|
}
|
|
711
710
|
|
|
711
|
+
static JSValue array_with_proto(JSContext *ctx, JSValue proto, uint32_t capacity) {
|
|
712
|
+
return array_of_shape(ctx, js_shape_root(ctx, &js_class_array, proto, 0), capacity); /* named properties on arrays are rare */
|
|
713
|
+
}
|
|
714
|
+
|
|
712
715
|
JSValue js_new_array(JSContext *ctx, uint32_t capacity) {
|
|
713
|
-
|
|
716
|
+
if (JS_UNLIKELY(!ctx->array_shape)) ctx->array_shape = js_shape_root(ctx, &js_class_array, ctx->intrinsics[JS_INTRINSIC_ARRAY_PROTOTYPE], 0);
|
|
717
|
+
return array_of_shape(ctx, ctx->array_shape, capacity);
|
|
714
718
|
}
|
|
715
719
|
|
|
716
720
|
JSValue js_new_array_from(JSContext *ctx, const JSValue *values, uint32_t n) {
|
|
@@ -821,7 +825,7 @@ JSValue js_get_value(JSContext *ctx, JSValue obj, JSValue key) {
|
|
|
821
825
|
}
|
|
822
826
|
|
|
823
827
|
int js_set_value(JSContext *ctx, JSValue obj, JSValue key, JSValue v, bool strict) {
|
|
824
|
-
if (js_is_object(obj)) return js_set(ctx, js_as_object(obj), key, v, obj, strict);
|
|
828
|
+
if (js_is_object(obj)) return js_key_is_index(key) ? js_set(ctx, js_as_object(obj), key, v, obj, strict) : js_set_prop_slow(ctx, obj, key, v, strict, NULL);
|
|
825
829
|
if (js_is_nullish(obj)) {
|
|
826
830
|
js_discard(nullish_error(ctx, obj, key, "set"));
|
|
827
831
|
return -1;
|
|
@@ -1045,6 +1049,11 @@ int js_set_prop_slow(JSContext *ctx, JSValue obj, JSValue key, JSValue v, bool s
|
|
|
1045
1049
|
JS_ASSERT_NOT_EXC(obj);
|
|
1046
1050
|
JS_ASSERT_NOT_EXC(v);
|
|
1047
1051
|
if (!js_is_object(obj) || js_key_is_index(key)) return js_set_value(ctx, obj, key, v, strict);
|
|
1052
|
+
JSPropCache none; /* no site (a computed key): only the shared cache */
|
|
1053
|
+
if (!ic) {
|
|
1054
|
+
none.kind = JS_IC_EMPTY;
|
|
1055
|
+
ic = &none;
|
|
1056
|
+
}
|
|
1048
1057
|
JSObject *o = js_as_object(obj);
|
|
1049
1058
|
if (ic->kind == JS_IC_ADD && o->shape == ic->shape && chain_holds(ctx, ic)) {
|
|
1050
1059
|
JSShape *next = ic->next; /* on the stack: kept alive if ensure_slot collects */
|
|
@@ -1083,8 +1092,10 @@ int js_set_prop_slow(JSContext *ctx, JSValue obj, JSValue key, JSValue v, bool s
|
|
|
1083
1092
|
return 1;
|
|
1084
1093
|
}
|
|
1085
1094
|
int r = js_set(ctx, o, key, v, obj, strict);
|
|
1086
|
-
/* a plain add (no setter or read-only property on the chain
|
|
1087
|
-
|
|
1095
|
+
/* a plain add (no setter or read-only property on the chain, or a prototype's writable data
|
|
1096
|
+
* property it shadows, as EventEmitter.prototype._events): remember the transition */
|
|
1097
|
+
bool shadows = l.holder && l.holder != o && (l.attrs & (JS_PROP_WRITABLE | JS_PROP_ACCESSOR)) == JS_PROP_WRITABLE;
|
|
1098
|
+
if (r == 1 && cacheable && (!l.holder || shadows) && !before->cls->define_own_property && !is_dictionary(o) &&
|
|
1088
1099
|
o->shape->parent == before && js_same_bits(o->shape->key, key)) {
|
|
1089
1100
|
JSPropCache c = { .kind = JS_IC_ADD, .depth = l.depth, .shape = before, .next = o->shape, .epoch = epoch };
|
|
1090
1101
|
memcpy(c.chain, l.chain, sizeof c.chain);
|
|
@@ -1098,9 +1109,32 @@ int js_set_prop_slow(JSContext *ctx, JSValue obj, JSValue key, JSValue v, bool s
|
|
|
1098
1109
|
|
|
1099
1110
|
/* ---- Generated code: computed keys, delete, literals --------------------------------- */
|
|
1100
1111
|
|
|
1112
|
+
/* Whether `key` can be a keyed site's: a property key as it is (a symbol, an interned string
|
|
1113
|
+
* that isn't an index), so that the same bits mean the same key. Makes the site its. */
|
|
1114
|
+
static bool take_site_key(JSContext *ctx, JSValue key, JSValue *site, JSPropCache *ic) {
|
|
1115
|
+
if (!js_is_symbol(key) && !(js_is_string(key) && js_is_atom(key))) return false;
|
|
1116
|
+
JSValue k = js_to_property_key(ctx, key); /* a primitive: no user code */
|
|
1117
|
+
if (!js_same_bits(k, key) || js_key_is_index(k)) return false;
|
|
1118
|
+
memset(ic, 0, sizeof *ic); /* its entries were for the old key */
|
|
1119
|
+
*site = key;
|
|
1120
|
+
return true;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
JSValue js_get_keyed_slow(JSContext *ctx, JSValue obj, JSValue key, JSValue *site, JSPropCache *ic) {
|
|
1124
|
+
if (take_site_key(ctx, key, site, ic)) return js_get_prop(ctx, obj, key, ic);
|
|
1125
|
+
return js_get_elem(ctx, obj, key);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
int js_set_keyed_slow(JSContext *ctx, JSValue obj, JSValue key, JSValue v, bool strict, JSValue *site, JSPropCache *ic) {
|
|
1129
|
+
if (take_site_key(ctx, key, site, ic)) return js_set_prop(ctx, obj, key, v, strict, ic);
|
|
1130
|
+
return js_set_elem(ctx, obj, key, v, strict);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1101
1133
|
JSValue js_get_elem(JSContext *ctx, JSValue obj, JSValue key) {
|
|
1102
1134
|
JS_ASSERT_NOT_EXC(obj);
|
|
1103
1135
|
JS_ASSERT_NOT_EXC(key);
|
|
1136
|
+
JSValue elem; /* a typed array's element: the component reads it inline */
|
|
1137
|
+
if (js_is_int32(key) && ctx->rt->typed_array_get && ctx->rt->typed_array_get(obj, js_as_int32(key), &elem)) return elem;
|
|
1104
1138
|
if (js_is_nullish(obj)) {
|
|
1105
1139
|
JSValue k = js_is_object(key) ? key : js_to_property_key(ctx, key); /* primitives only: no user code */
|
|
1106
1140
|
if (js_is_exception(k)) return JS_EXCEPTION;
|
|
@@ -1113,6 +1147,8 @@ JSValue js_get_elem(JSContext *ctx, JSValue obj, JSValue key) {
|
|
|
1113
1147
|
|
|
1114
1148
|
int js_set_elem(JSContext *ctx, JSValue obj, JSValue key, JSValue v, bool strict) {
|
|
1115
1149
|
JS_ASSERT_NOT_EXC(v);
|
|
1150
|
+
/* a Number into a typed array's element: no ToNumber code to run, the component stores it inline */
|
|
1151
|
+
if (js_is_int32(key) && js_is_number(v) && ctx->rt->typed_array_set && ctx->rt->typed_array_set(obj, js_as_int32(key), js_as_number(v))) return 1;
|
|
1116
1152
|
if (js_is_nullish(obj)) {
|
|
1117
1153
|
JSValue k = js_is_object(key) ? js_empty_string() : js_to_property_key(ctx, key);
|
|
1118
1154
|
if (js_is_exception(k)) return -1;
|
package/runtime/src/typedarray.c
CHANGED
|
@@ -1234,6 +1234,26 @@ static double hook_typed_array_length(JSValue v) {
|
|
|
1234
1234
|
return out_of_bounds(as_ta(v)) ? -1 : (double)ta_length(as_ta(v));
|
|
1235
1235
|
}
|
|
1236
1236
|
|
|
1237
|
+
/* An element the core may read or write inline: of a typed array, a valid index (§10.4.5.15
|
|
1238
|
+
* IsValidIntegerIndex), a Number element. Its own data property: no prototype, no code runs. */
|
|
1239
|
+
static bool inline_elem(JSValue v, int32_t i) {
|
|
1240
|
+
if (!is_ta(v) || i < 0) return false;
|
|
1241
|
+
const JSTypedArray *ta = as_ta(v);
|
|
1242
|
+
return !is_bigint_type(ta->type) && (size_t)i < ta_length(ta);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
static bool hook_typed_array_get(JSValue v, int32_t i, JSValue *out) {
|
|
1246
|
+
if (!inline_elem(v, i)) return false;
|
|
1247
|
+
*out = js_number(load_number(as_ta(v), (size_t)i));
|
|
1248
|
+
return true;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
static bool hook_typed_array_set(JSValue v, int32_t i, double d) {
|
|
1252
|
+
if (!inline_elem(v, i) || immutable(as_ta(v))) return false;
|
|
1253
|
+
store(as_ta(v), (size_t)i, d);
|
|
1254
|
+
return true;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1237
1257
|
static bool hook_view_bytes(JSValue v, uint8_t **data, size_t *length) {
|
|
1238
1258
|
return !js_is_array_buffer(v) && js_buffer_source_bytes(v, data, length);
|
|
1239
1259
|
}
|
|
@@ -1330,6 +1350,9 @@ static void install_typedarray(JSContext *ctx, JSObject *global) {
|
|
|
1330
1350
|
ctx->rt->is_typed_array = hook_is_typed_array;
|
|
1331
1351
|
ctx->rt->typed_array_length = hook_typed_array_length;
|
|
1332
1352
|
ctx->rt->view_bytes = hook_view_bytes;
|
|
1353
|
+
ctx->rt->typed_array_get = hook_typed_array_get;
|
|
1354
|
+
ctx->rt->typed_array_class = &ta_class;
|
|
1355
|
+
ctx->rt->typed_array_set = hook_typed_array_set;
|
|
1333
1356
|
}
|
|
1334
1357
|
|
|
1335
1358
|
const JSComponent js_component_typedarray = { "typedarray", install_typedarray };
|