diff --git a/src/ant.c b/src/ant.c index ea79c51..f849243 100644 --- a/src/ant.c +++ b/src/ant.c @@ -11267,6 +11267,20 @@ ant_value_t js_promise_then(ant_t *js, ant_value_t promise, ant_value_t on_fulfi return result; } +static void js_mark_promise_rejection_handled_chain(ant_t *js, ant_value_t promise) { + ant_value_t current = promise; + + while (vtype(current) == T_PROMISE) { + ant_promise_state_t *pd = get_promise_data(js, current, false); + if (!pd) break; + + if (pd->unhandled_reported) js_fire_rejection_handled(js, current, pd->value); + pd->has_rejection_handler = true; + pd->unhandled_reported = false; + current = pd->trigger_parent; + } +} + static inline ant_value_t js_get_thenable_then(ant_t *js, ant_value_t value) { if (!is_object_type(value)) return js_mkundef(); return js_getprop_fallback(js, value, "then"); @@ -11294,10 +11308,7 @@ js_await_result_t js_promise_await_coroutine(ant_t *js, ant_value_t promise, cor return result; } - if (pd->unhandled_reported) js_fire_rejection_handled(js, promise, pd->value); - pd->has_rejection_handler = true; - pd->unhandled_reported = false; - + js_mark_promise_rejection_handled_chain(js, promise); if (pd->state == 0) gc_root_pending_promise(js_obj_ptr(js_as_obj(promise))); else queue_promise_trigger(js, promise); @@ -11405,11 +11416,8 @@ void js_resolve_promise(ant_t *js, ant_value_t p, ant_value_t val) { } gc_write_barrier(js, js_obj_ptr(js_as_obj(val)), p); - if (src_pd->unhandled_reported) js_fire_rejection_handled(js, val, src_pd->value); + js_mark_promise_rejection_handled_chain(js, val); - src_pd->has_rejection_handler = true; - src_pd->unhandled_reported = false; - if (src_pd->state == 0) gc_root_pending_promise(js_obj_ptr(js_as_obj(val))); else queue_promise_trigger(js, val); GC_ROOT_RESTORE(js, root_mark); @@ -11666,17 +11674,14 @@ static ant_value_t builtin_promise_then(ant_t *js, ant_value_t *args, int nargs) GC_ROOT_RESTORE(js, root_mark); return js_mkerr(js, "out of memory"); } - + gc_write_barrier(js, js_obj_ptr(js_as_obj(p)), nextP); gc_write_barrier(js, js_obj_ptr(js_as_obj(p)), onFulfilled); gc_write_barrier(js, js_obj_ptr(js_as_obj(p)), onRejected); - - if (vtype(onRejected) == T_FUNC || vtype(onRejected) == T_CFUNC) { - if (pd->unhandled_reported) js_fire_rejection_handled(js, p, pd->value); - pd->has_rejection_handler = true; - pd->unhandled_reported = false; - } - + + if (vtype(onRejected) == T_FUNC || vtype(onRejected) == T_CFUNC) + js_mark_promise_rejection_handled_chain(js, p); + if (pd->state == 0) gc_root_pending_promise(js_obj_ptr(p)); } @@ -12469,9 +12474,7 @@ static ant_value_t builtin_Promise_any(ant_t *js, ant_value_t *args, int nargs) ant_promise_state_t *pd = get_promise_data(js, item, false); if (pd) { - pd->has_rejection_handler = true; - pd->unhandled_reported = false; - + js_mark_promise_rejection_handled_chain(js, item); if (pd->state == 1) { promise_any_try_resolve(js, tracker, pd->value); GC_ROOT_RESTORE(js, root_mark); @@ -12999,7 +13002,7 @@ ant_value_t js_get_module_import_binding(ant_t *js) { ant_value_t module_ctx = js_get_execution_module_ctx(js); ant_value_t import_meta = js_get_module_ctx_import_meta(js, module_ctx); - + GC_ROOT_PIN(js, module_ctx); GC_ROOT_PIN(js, import_meta); diff --git a/src/silver/glue.c b/src/silver/glue.c index d5abf00..1d6ac79 100644 --- a/src/silver/glue.c +++ b/src/silver/glue.c @@ -618,7 +618,7 @@ ant_value_t jit_helper_closure( ant_value_t func_obj = mkobj(js, 0); closure->func_obj = func_obj; - ant_value_t module_ctx = js_module_eval_active_ctx(js); + ant_value_t module_ctx = sv_get_current_closure_module_ctx(js, mkval(T_FUNC, (uintptr_t)parent_closure)); js_mark_constructor(func_obj, !child->is_arrow && !child->is_method && !child->is_generator); js_setprop(js, func_obj, js->length_str, tov((double)child->param_count)); diff --git a/src/silver/ops/coercion.h b/src/silver/ops/coercion.h index ca21c6e..c0fcfbd 100644 --- a/src/silver/ops/coercion.h +++ b/src/silver/ops/coercion.h @@ -58,12 +58,17 @@ static inline void sv_op_is_null(sv_vm_t *vm) { static inline ant_value_t sv_op_import(sv_vm_t *vm, ant_t *js) { ant_value_t specifier = vm->stack[--vm->sp]; - ant_value_t import_fn = js_getprop_fallback(js, js->global, "import"); + ant_value_t import_fn = js_get_module_import_binding(js); + + if (vtype(import_fn) != T_FUNC && vtype(import_fn) != T_CFUNC) + import_fn = js_getprop_fallback(js, js->global, "import"); + if (vtype(import_fn) == T_FUNC || vtype(import_fn) == T_CFUNC) { ant_value_t result = sv_vm_call(vm, js, import_fn, js->global, &specifier, 1, NULL, false); if (!is_err(result)) vm->stack[vm->sp++] = result; return result; } + vm->stack[vm->sp++] = mkval(T_UNDEF, 0); return tov(0); } diff --git a/src/silver/ops/upvalues.h b/src/silver/ops/upvalues.h index b8d5935..8ded40f 100644 --- a/src/silver/ops/upvalues.h +++ b/src/silver/ops/upvalues.h @@ -1,8 +1,9 @@ #ifndef SV_UPVALUES_H #define SV_UPVALUES_H -#include "silver/engine.h" +#include "internal.h" #include "descriptors.h" +#include "silver/engine.h" static inline ant_value_t sv_setup_function_prototype_with_parent( ant_t *js, ant_value_t func_obj, @@ -29,6 +30,15 @@ static inline ant_value_t sv_setup_function_prototype_with_parent( return js_mkundef(); } +static inline ant_value_t sv_get_current_closure_module_ctx(ant_t *js, ant_value_t parent_func) { + if (vtype(parent_func) == T_FUNC) { + ant_value_t module_ctx = js_get_slot(js_func_obj(parent_func), SLOT_MODULE_CTX); + if (is_object_type(module_ctx)) return module_ctx; + } + + return js_module_eval_active_ctx(js); +} + static inline ant_value_t sv_op_get_upval( sv_vm_t *vm, sv_frame_t *frame, ant_t *js, uint8_t *ip @@ -122,7 +132,7 @@ static inline ant_value_t sv_op_closure( ant_value_t func_obj = mkobj(js, 0); closure->func_obj = func_obj; - ant_value_t module_ctx = js_module_eval_active_ctx(js); + ant_value_t module_ctx = sv_get_current_closure_module_ctx(js, frame->callee); js_mark_constructor(func_obj, !child->is_arrow && !child->is_method && !child->is_generator); js_setprop(js, func_obj, js->length_str, tov((double)child->param_count)); diff --git a/src/streams/pipes.c b/src/streams/pipes.c index 17cc47b..90ed936 100644 --- a/src/streams/pipes.c +++ b/src/streams/pipes.c @@ -5,6 +5,7 @@ #include "internal.h" #include "descriptors.h" +#include "gc/roots.h" #include "silver/engine.h" #include "modules/assert.h" #include "modules/abort.h" @@ -13,28 +14,38 @@ #include "streams/writable.h" #include "modules/structured-clone.h" +typedef struct { + bool settled; + bool shutting_down; + bool in_flight; + bool prevent_close; + bool prevent_abort; + bool prevent_cancel; +} pipe_state_t; + static void pipes_chain_promise( ant_t *js, ant_value_t value, ant_value_t on_resolve, ant_value_t on_reject ) { + GC_ROOT_SAVE(root_mark, js); + GC_ROOT_PIN(js, value); + GC_ROOT_PIN(js, on_resolve); + GC_ROOT_PIN(js, on_reject); + ant_value_t promise = value; + GC_ROOT_PIN(js, promise); if (vtype(promise) != T_PROMISE) { promise = js_mkpromise(js); + GC_ROOT_PIN(js, promise); js_resolve_promise(js, promise, value); } - js_promise_then(js, promise, on_resolve, on_reject); + ant_value_t then_result = js_promise_then(js, promise, on_resolve, on_reject); + GC_ROOT_PIN(js, then_result); + promise_mark_handled(then_result); + GC_ROOT_RESTORE(js, root_mark); } -typedef struct { - bool settled; - bool shutting_down; - bool in_flight; - bool prevent_close; - bool prevent_abort; - bool prevent_cancel; -} pipe_state_t; - static void pipe_state_finalize(ant_t *js, ant_object_t *obj) { if (!obj->extra_slots) return; ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; @@ -93,7 +104,7 @@ static void pipes_release_reader(ant_t *js, ant_value_t reader_obj) { js_reject_promise(js, new_closed, release_err); promise_mark_handled(new_closed); - js_set_slot(reader_obj, SLOT_RS_CLOSED, new_closed); + js_set_slot_wb(js, reader_obj, SLOT_RS_CLOSED, new_closed); js_set_slot(stream_obj, SLOT_CTOR, js_mkundef()); js_set_slot(reader_obj, SLOT_ENTRIES, js_mkundef()); } @@ -107,12 +118,12 @@ static void pipes_release_writer(ant_t *js, ant_value_t writer_obj) { js_reject_promise(js, ready, rel_err); promise_mark_handled(ready); - js_set_slot(writer_obj, SLOT_WS_READY, ready); + js_set_slot_wb(js, writer_obj, SLOT_WS_READY, ready); ant_value_t closed = js_mkpromise(js); js_reject_promise(js, closed, rel_err); promise_mark_handled(closed); - js_set_slot(writer_obj, SLOT_RS_CLOSED, closed); + js_set_slot_wb(js, writer_obj, SLOT_RS_CLOSED, closed); js_set_slot(ws_obj, SLOT_CTOR, js_mkundef()); js_set_slot(writer_obj, SLOT_ENTRIES, js_mkundef()); } @@ -705,10 +716,10 @@ static ant_value_t tee_branch_cancel(ant_t *js, ant_value_t *args, int nargs) { if (is_b1) st->canceled1 = true; else st->canceled2 = true; - js_set_slot(state, reason_slot, reason); + js_set_slot_wb(js, state, reason_slot, reason); ant_value_t promise = js_mkpromise(js); - js_set_slot(state, promise_slot, promise); + js_set_slot_wb(js, state, promise_slot, promise); if (st->done) { js_resolve_promise(js, promise, js_mkundef()); diff --git a/src/streams/transform.c b/src/streams/transform.c index 0950f00..552f684 100644 --- a/src/streams/transform.c +++ b/src/streams/transform.c @@ -7,6 +7,7 @@ #include "internal.h" #include "descriptors.h" +#include "gc/roots.h" #include "silver/engine.h" #include "modules/assert.h" #include "modules/symbol.h" @@ -180,8 +181,8 @@ static inline void ts_set_flushing(ant_value_t ts_obj, bool flushing) { js_set_slot(ts_obj, SLOT_WS_CLOSE, flushing ? js_true : js_false); } -static inline void ts_set_cancel_state(ant_value_t ts_obj, ant_value_t promise, bool started_by_abort, bool has_user_handler) { - js_set_slot(ts_obj, SLOT_RS_CANCEL, promise); +static inline void ts_set_cancel_state(ant_t *js, ant_value_t ts_obj, ant_value_t promise, bool started_by_abort, bool has_user_handler) { + js_set_slot_wb(js, ts_obj, SLOT_RS_CANCEL, promise); js_set_slot(ts_obj, SLOT_WS_ABORT, started_by_abort ? js_true : js_false); js_set_slot(ts_obj, SLOT_RS_SIZE, js_mkundef()); js_set_slot(ts_obj, SLOT_WS_WRITE, js_false); @@ -211,14 +212,23 @@ static ant_value_t ts_take_thrown_or(ant_t *js, ant_value_t fallback) { } static void ts_chain_promise(ant_t *js, ant_value_t val, ant_value_t res_fn, ant_value_t rej_fn) { + GC_ROOT_SAVE(root_mark, js); + GC_ROOT_PIN(js, val); + GC_ROOT_PIN(js, res_fn); + GC_ROOT_PIN(js, rej_fn); + ant_value_t promise = val; + GC_ROOT_PIN(js, promise); if (vtype(promise) != T_PROMISE) { promise = js_mkpromise(js); + GC_ROOT_PIN(js, promise); js_resolve_promise(js, promise, val); } ant_value_t then_result = js_promise_then(js, promise, res_fn, rej_fn); + GC_ROOT_PIN(js, then_result); promise_mark_handled(then_result); + GC_ROOT_RESTORE(js, root_mark); } static void ts_error(ant_t *js, ant_value_t ts_obj, ant_value_t e) { @@ -261,7 +271,7 @@ static void ts_set_backpressure(ant_t *js, ant_value_t ts_obj, bool backpressure if (vtype(bp) == T_PROMISE) js_resolve_promise(js, bp, js_mkundef()); } ant_value_t new_bp = js_mkpromise(js); - js_set_slot(ts_obj, SLOT_AUX, new_bp); + js_set_slot_wb(js, ts_obj, SLOT_AUX, new_bp); ts_set_bp_flag(ts_obj, backpressure); } @@ -291,7 +301,7 @@ ant_value_t ts_ctrl_enqueue(ant_t *js, ant_value_t ctrl_obj, ant_value_t chunk) void ts_ctrl_error(ant_t *js, ant_value_t ctrl_obj, ant_value_t e) { ant_value_t ts_obj = ts_ctrl_stream(ctrl_obj); if (vtype(ts_cancel_promise(ts_obj)) == T_PROMISE && ts_cancel_has_user_handler(ts_obj)) - js_set_slot(ts_obj, SLOT_RS_SIZE, e); + js_set_slot_wb(js, ts_obj, SLOT_RS_SIZE, e); ts_error(js, ts_obj, e); ts_error_writable_and_unblock_write(js, ts_obj, e); } @@ -389,7 +399,7 @@ static ant_value_t ts_run_cancel_algorithm(ant_t *js, ant_value_t ts_obj, ant_va ant_value_t p = js_mkpromise(js); promise_mark_handled(p); - ts_set_cancel_state(ts_obj, p, started_by_abort, is_callable(cancel_fn)); + ts_set_cancel_state(js, ts_obj, p, started_by_abort, is_callable(cancel_fn)); ts_ctrl_clear_algorithms(ts_controller(ts_obj)); ant_value_t result = js_mkundef(); @@ -467,7 +477,7 @@ static ant_value_t ts_abort_cancel_resolve(ant_t *js, ant_value_t *args, int nar return js_mkundef(); } - if (ts_cancel_joined_abort(ts_obj)) js_set_slot(ts_obj, SLOT_RS_SIZE, reason); + if (ts_cancel_joined_abort(ts_obj)) js_set_slot_wb(js, ts_obj, SLOT_RS_SIZE, reason); ts_error(js, ts_obj, reason); if (ts_cancel_joined_abort(ts_obj)) js_reject_promise(js, p, reason); @@ -549,7 +559,7 @@ static ant_value_t ts_sink_write(ant_t *js, ant_value_t *args, int nargs) { ant_value_t finish_p = js_mkpromise(js); promise_mark_handled(finish_p); - js_set_slot(ctrl_obj, SLOT_RS_PULL, finish_p); + js_set_slot_wb(js, ctrl_obj, SLOT_RS_PULL, finish_p); if (ts_get_backpressure(ts_obj)) { ant_value_t wrapper = js_mkobj(js); @@ -995,7 +1005,7 @@ ant_value_t js_ts_ctor(ant_t *js, ant_value_t *args, int nargs) { js_set_slot(ts_obj, SLOT_CTOR, ws_obj); ant_value_t bp_promise = js_mkpromise(js); - js_set_slot(ts_obj, SLOT_AUX, bp_promise); + js_set_slot_wb(js, ts_obj, SLOT_AUX, bp_promise); ts_set_backpressure(js, ts_obj, true); diff --git a/src/streams/writable.c b/src/streams/writable.c index 7ead6bc..df6f9fc 100644 --- a/src/streams/writable.c +++ b/src/streams/writable.c @@ -7,6 +7,7 @@ #include "internal.h" #include "descriptors.h" +#include "gc/roots.h" #include "silver/engine.h" #include "modules/symbol.h" #include "modules/assert.h" @@ -197,14 +198,23 @@ static ant_value_t ws_write_reqs_shift(ant_t *js, ant_value_t stream_obj) { } static void ws_chain_promise(ant_t *js, ant_value_t val, ant_value_t res_fn, ant_value_t rej_fn) { + GC_ROOT_SAVE(root_mark, js); + GC_ROOT_PIN(js, val); + GC_ROOT_PIN(js, res_fn); + GC_ROOT_PIN(js, rej_fn); + ant_value_t promise = val; + GC_ROOT_PIN(js, promise); if (vtype(promise) != T_PROMISE) { promise = js_mkpromise(js); + GC_ROOT_PIN(js, promise); js_resolve_promise(js, promise, val); } ant_value_t then_result = js_promise_then(js, promise, res_fn, rej_fn); + GC_ROOT_PIN(js, then_result); promise_mark_handled(then_result); + GC_ROOT_RESTORE(js, root_mark); } static void ws_default_controller_clear_algorithms(ant_value_t ctrl_obj) { @@ -238,14 +248,14 @@ static void ws_writer_replace_ready_promise_rejected(ant_t *js, ant_value_t writ ant_value_t ready = js_mkpromise(js); js_reject_promise(js, ready, error); promise_mark_handled(ready); - js_set_slot(writer_obj, SLOT_WS_READY, ready); + js_set_slot_wb(js, writer_obj, SLOT_WS_READY, ready); } static void ws_writer_replace_closed_promise_rejected(ant_t *js, ant_value_t writer_obj, ant_value_t error) { ant_value_t closed = js_mkpromise(js); js_reject_promise(js, closed, error); promise_mark_handled(closed); - js_set_slot(writer_obj, SLOT_RS_CLOSED, closed); + js_set_slot_wb(js, writer_obj, SLOT_RS_CLOSED, closed); } static void ws_writer_reject_ready_promise(ant_t *js, ant_value_t writer_obj, ant_value_t error) { @@ -266,7 +276,7 @@ static void writable_stream_start_erroring(ant_t *js, ant_value_t stream_obj, an ws_controller_t *ctrl = ws_get_controller(ctrl_obj); stream->state = WS_STATE_ERRORING; - js_set_slot(stream_obj, SLOT_AUX, reason); + js_set_slot_wb(js, stream_obj, SLOT_AUX, reason); ant_value_t signal_ac = ws_ctrl_signal(ctrl_obj); if (is_object_type(signal_ac)) { @@ -396,7 +406,7 @@ static void writable_stream_update_backpressure(ant_t *js, ant_value_t stream_ob if (backpressure) { ant_value_t ready = js_mkpromise(js); promise_mark_handled(ready); - js_set_slot(writer_obj, SLOT_WS_READY, ready); + js_set_slot_wb(js, writer_obj, SLOT_WS_READY, ready); } else { ant_value_t ready = ws_writer_ready(writer_obj); if (!is_undefined(ready)) js_resolve_promise(js, ready, js_mkundef()); @@ -453,12 +463,12 @@ static void writable_stream_finish_in_flight_close_with_error(ant_t *js, ant_val static void writable_stream_mark_first_write_in_flight(ant_t *js, ant_value_t stream_obj) { ant_value_t wr = ws_write_reqs_shift(js, stream_obj); - js_set_slot(stream_obj, SLOT_DEFAULT, wr); + js_set_slot_wb(js, stream_obj, SLOT_DEFAULT, wr); } -static void writable_stream_mark_close_in_flight(ant_value_t stream_obj) { +static void writable_stream_mark_close_in_flight(ant_t *js, ant_value_t stream_obj) { ant_value_t cr = ws_stream_close_request(stream_obj); - js_set_slot(stream_obj, SLOT_WS_ABORT, cr); + js_set_slot_wb(js, stream_obj, SLOT_WS_ABORT, cr); js_set_slot(stream_obj, SLOT_WS_CLOSE, js_mkundef()); } @@ -546,7 +556,7 @@ static ant_value_t ws_process_close_reject(ant_t *js, ant_value_t *args, int nar static void ws_default_controller_process_close(ant_t *js, ant_value_t ctrl_obj) { ant_value_t stream_obj = ws_ctrl_stream(ctrl_obj); - writable_stream_mark_close_in_flight(stream_obj); + writable_stream_mark_close_in_flight(js, stream_obj); ws_ctrl_queue_shift(js, ctrl_obj); ws_controller_t *ctrl = ws_get_controller(ctrl_obj); @@ -664,7 +674,7 @@ ant_value_t writable_stream_close(ant_t *js, ant_value_t stream_obj) { } ant_value_t promise = js_mkpromise(js); - js_set_slot(stream_obj, SLOT_WS_CLOSE, promise); + js_set_slot_wb(js, stream_obj, SLOT_WS_CLOSE, promise); ant_value_t writer_obj = ws_stream_writer(stream_obj); if (ws_is_writer(writer_obj) && stream->backpressure && stream->state == WS_STATE_WRITABLE) { @@ -747,7 +757,7 @@ ant_value_t writable_stream_abort(ant_t *js, ant_value_t stream_obj, ant_value_t ant_value_t promise = js_mkpromise(js); stream->has_pending_abort = true; stream->pending_abort_was_already_erroring = was_already_erroring; - js_set_slot(stream_obj, SLOT_WS_READY, promise); + js_set_slot_wb(js, stream_obj, SLOT_WS_READY, promise); if (!was_already_erroring) writable_stream_start_erroring(js, stream_obj, reason);