diff --git a/cont.c b/cont.c index 072ae4562f..ae68da4e83 100644 --- a/cont.c +++ b/cont.c @@ -1369,6 +1369,7 @@ cont_init(rb_context_t *cont, rb_thread_t *th) /* save thread context */ cont_save_thread(cont, th); cont->saved_ec.thread_ptr = th; + cont->saved_ec.tag = NULL; cont->saved_ec.local_storage = NULL; cont->saved_ec.local_storage_recursive_hash = Qnil; cont->saved_ec.local_storage_recursive_hash_for_trace = Qnil; diff --git a/eval_intern.h b/eval_intern.h index ab0577e8ed..49229fa82d 100644 --- a/eval_intern.h +++ b/eval_intern.h @@ -102,11 +102,11 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval _tag.tag = Qundef; \ _tag.prev = _ec->tag; \ _tag.lock_rec = rb_ec_vm_lock_rec(_ec); \ - rb_vm_tag_jmpbuf_init(&_tag.buf); \ + rb_vm_tag_jmpbuf_init(&_tag); #define EC_POP_TAG() \ _ec->tag = _tag.prev; \ - rb_vm_tag_jmpbuf_deinit(&_tag.buf); \ + rb_vm_tag_jmpbuf_deinit(&_tag); \ } while (0) #define EC_TMPPOP_TAG() \ diff --git a/vm_core.h b/vm_core.h index d9159f5ccf..28d742feed 100644 --- a/vm_core.h +++ b/vm_core.h @@ -946,37 +946,16 @@ typedef void *rb_jmpbuf_t[5]; Therefore, we allocates the buffer on the heap on such environments. */ -typedef rb_jmpbuf_t *rb_vm_tag_jmpbuf_t; +typedef struct _rb_vm_tag_jmpbuf { + struct _rb_vm_tag_jmpbuf *next; + rb_jmpbuf_t buf; +} *rb_vm_tag_jmpbuf_t; -#define RB_VM_TAG_JMPBUF_GET(buf) (*buf) - -static inline void -rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf) -{ - *jmpbuf = ruby_xmalloc(sizeof(rb_jmpbuf_t)); -} - -static inline void -rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf) -{ - ruby_xfree(*jmpbuf); -} +#define RB_VM_TAG_JMPBUF_GET(jmpbuf) ((jmpbuf)->buf) #else typedef rb_jmpbuf_t rb_vm_tag_jmpbuf_t; -#define RB_VM_TAG_JMPBUF_GET(buf) (buf) - -static inline void -rb_vm_tag_jmpbuf_init(rb_vm_tag_jmpbuf_t *jmpbuf) -{ - // no-op -} - -static inline void -rb_vm_tag_jmpbuf_deinit(const rb_vm_tag_jmpbuf_t *jmpbuf) -{ - // no-op -} +#define RB_VM_TAG_JMPBUF_GET(jmpbuf) (jmpbuf) #endif /* @@ -992,6 +971,54 @@ struct rb_vm_tag { unsigned int lock_rec; }; +#if defined(__wasm__) && !defined(__EMSCRIPTEN__) +static inline void +_rb_vm_tag_jmpbuf_deinit_internal(rb_vm_tag_jmpbuf_t jmpbuf) +{ + rb_vm_tag_jmpbuf_t buf = jmpbuf; + while (buf != NULL) { + rb_vm_tag_jmpbuf_t next = buf->next; + ruby_xfree(buf); + buf = next; + } +} + +static inline void +rb_vm_tag_jmpbuf_init(struct rb_vm_tag *tag) +{ + if (tag->prev != NULL && tag->prev->buf->next != NULL) { + _rb_vm_tag_jmpbuf_deinit_internal(tag->prev->buf->next); + tag->prev->buf->next = NULL; + } + tag->buf = ruby_xmalloc(sizeof *tag->buf); + tag->buf->next = NULL; + if (tag->prev != NULL) { + tag->prev->buf->next = tag->buf; + } +} + +static inline void +rb_vm_tag_jmpbuf_deinit(struct rb_vm_tag *tag) +{ + if (tag->prev != NULL) { + tag->prev->buf->next = NULL; + } + _rb_vm_tag_jmpbuf_deinit_internal(tag->buf); +} +#else +static inline void +rb_vm_tag_jmpbuf_init(struct rb_vm_tag *tag) +{ + // no-op +} + +static inline void +rb_vm_tag_jmpbuf_deinit(struct rb_vm_tag *tag) +{ + // no-op +} +#endif + STATIC_ASSERT(rb_vm_tag_buf_offset, offsetof(struct rb_vm_tag, buf) > 0); STATIC_ASSERT(rb_vm_tag_buf_end, offsetof(struct rb_vm_tag, buf) + sizeof(rb_vm_tag_jmpbuf_t) <