visaljs 0.0.8 → 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.
Files changed (54) hide show
  1. package/README.md +6 -3
  2. package/THIRD_PARTY_LICENSES +1 -1
  3. package/cli.js +2782 -770
  4. package/node/include/js_node.h +1 -0
  5. package/node/prelude/_http_agent.js +5 -0
  6. package/node/prelude/_http_server.js +7 -0
  7. package/node/prelude/dns.js +7 -1
  8. package/node/prelude/events.js +7 -3
  9. package/node/prelude/http.js +693 -285
  10. package/node/prelude/https.js +14 -3
  11. package/node/prelude/internal/events_extras.js +2 -5
  12. package/node/prelude/internal/features.js +17 -0
  13. package/node/prelude/internal/http_agent.js +88 -2
  14. package/node/prelude/internal/http_chars.ts +22 -0
  15. package/node/prelude/internal/http_symbols.js +3 -0
  16. package/node/prelude/internal/net_bound.js +123 -0
  17. package/node/prelude/internal/net_onread.js +73 -0
  18. package/node/prelude/internal/net_tos.js +54 -0
  19. package/node/prelude/internal/perf_observe.js +7 -1
  20. package/node/prelude/internal/tls/wrap.js +2 -1
  21. package/node/prelude/module.js +42 -18
  22. package/node/prelude/net.js +212 -61
  23. package/node/prelude/perf_hooks.js +4 -0
  24. package/node/src/host_http.c +151 -21
  25. package/node/src/host_net.c +75 -9
  26. package/node/src/host_sys.c +9 -0
  27. package/package.json +1 -1
  28. package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
  29. package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
  30. package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
  31. package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
  32. package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
  33. package/runtime/include/js_atoms.h +4 -0
  34. package/runtime/include/js_buffer.h +185 -0
  35. package/runtime/include/js_builtins.h +53 -0
  36. package/runtime/include/js_exception.h +3 -0
  37. package/runtime/include/js_function.h +1 -1
  38. package/runtime/include/js_object.h +21 -3
  39. package/runtime/include/js_ops.h +27 -0
  40. package/runtime/include/js_runtime.h +1 -0
  41. package/runtime/include/js_web.h +3 -3
  42. package/runtime/include/jscontext.h +15 -0
  43. package/runtime/src/atoms.c +37 -3
  44. package/runtime/src/builtins.c +17 -4
  45. package/runtime/src/events.c +19 -0
  46. package/runtime/src/function.c +37 -10
  47. package/runtime/src/gc.c +7 -5
  48. package/runtime/src/internal.h +4 -4
  49. package/runtime/src/iterator.c +5 -1
  50. package/runtime/src/object.c +42 -6
  51. package/runtime/src/regexp.c +569 -12
  52. package/runtime/src/shape.c +68 -1
  53. package/runtime/src/typedarray.c +23 -0
  54. package/runtime/src/weak.c +95 -24
@@ -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
- JSFunction *f = js_as_function(fv);
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
- return fn->entry(fn->flags & JS_FN_PROXY ? ctx : fn->realm, f, JS_UNDEFINED, argc, argv, new_target);
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]);
@@ -1910,14 +1912,14 @@ static JS_NOINLINE void collect(JSContext *ctx, const void *stack_low, bool full
1910
1912
  mark_roots(rt, trc);
1911
1913
  mark_stack(trc);
1912
1914
  drain(trc);
1913
- while (js_weak_ephemerons(rt, trc)) drain(trc); /* a WeakMap value lives if its key does */
1915
+ while (js_weak_ephemerons(rt, trc, full)) drain(trc); /* a WeakMap value lives if its key does */
1914
1916
  h->mark_stack = trc->stack; /* kept for the next collection */
1915
1917
  h->mark_stack_cap = trc->cap;
1916
1918
  double marked = js_os_now_ms_precise();
1917
1919
 
1918
- js_weak_sweep(rt);
1919
- js_atoms_sweep(rt); /* weak references, before anything is freed */
1920
- js_shapes_sweep(rt);
1920
+ js_weak_sweep(rt, full);
1921
+ js_atoms_sweep(rt, full); /* weak references, before anything is freed */
1922
+ js_shapes_sweep(rt, full);
1921
1923
  js_prop_caches_sweep(rt);
1922
1924
  double weak = js_os_now_ms_precise();
1923
1925
 
@@ -12,7 +12,7 @@
12
12
  bool js_gc_is_marked(const JSCell *c);
13
13
 
14
14
  /* Shapes (shape.c): weak processing after marking, and teardown. */
15
- void js_shapes_sweep(JSRuntime *rt);
15
+ void js_shapes_sweep(JSRuntime *rt, bool full);
16
16
  void js_shapes_free(JSRuntime *rt);
17
17
  /* Inline caches (object.c): weak processing after marking, and teardown. */
18
18
  void js_prop_caches_sweep(JSRuntime *rt);
@@ -55,8 +55,8 @@ void js_promise_then_internal(JSContext *ctx, JSValue promise, JSValue on_fulfil
55
55
  * marked anything), weak processing after marking, the kept-alive roots, teardown;
56
56
  * ClearKeptObjects; the FinalizationRegistry cleanup tasks (0, or -1 after an uncaught
57
57
  * error); the realm's WeakMap, WeakSet, WeakRef, FinalizationRegistry. */
58
- bool js_weak_ephemerons(JSRuntime *rt, JSTracer *trc);
59
- void js_weak_sweep(JSRuntime *rt);
58
+ bool js_weak_ephemerons(JSRuntime *rt, JSTracer *trc, bool full);
59
+ void js_weak_sweep(JSRuntime *rt, bool full);
60
60
  void js_weak_trace_roots(JSRuntime *rt, JSTracer *trc);
61
61
  void js_weak_free(JSRuntime *rt);
62
62
  void js_clear_kept_objects(JSRuntime *rt);
@@ -64,7 +64,7 @@ int js_run_finalization_cleanups(JSContext *ctx);
64
64
 
65
65
  /* Atom table lifecycle (atoms.c). */
66
66
  void js_atoms_init(JSRuntime *rt);
67
- void js_atoms_sweep(JSRuntime *rt); /* weak processing: drop unmarked atoms */
67
+ void js_atoms_sweep(JSRuntime *rt, bool full); /* weak processing: drop unmarked atoms */
68
68
  void js_atoms_free(JSRuntime *rt);
69
69
 
70
70
  /* Cell classes defined outside gc.c: each kind's name and finalizer. The marker visits these kinds
@@ -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
- value = array_step(ctx, r->iterator, r->index, KIND_VALUES);
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;
@@ -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 array_with_proto(JSContext *ctx, JSValue proto, uint32_t capacity) {
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
- return array_with_proto(ctx, ctx->intrinsics[JS_INTRINSIC_ARRAY_PROTOTYPE], capacity);
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): remember the transition */
1087
- if (r == 1 && cacheable && !l.holder && !before->cls->define_own_property && !is_dictionary(o) &&
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;