aboutsummaryrefslogtreecommitdiff
path: root/deps/lightrec/recompiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/lightrec/recompiler.c')
-rw-r--r--deps/lightrec/recompiler.c110
1 files changed, 59 insertions, 51 deletions
diff --git a/deps/lightrec/recompiler.c b/deps/lightrec/recompiler.c
index 379881a..e60889c 100644
--- a/deps/lightrec/recompiler.c
+++ b/deps/lightrec/recompiler.c
@@ -16,6 +16,7 @@
#include "interpreter.h"
#include "lightrec-private.h"
#include "memmanager.h"
+#include "slist.h"
#include <errno.h>
#include <stdatomic.h>
@@ -25,7 +26,7 @@
struct block_rec {
struct block *block;
- struct block_rec *next;
+ struct slist_elm slist;
};
struct recompiler {
@@ -35,31 +36,19 @@ struct recompiler {
pthread_mutex_t mutex;
bool stop;
struct block *current_block;
- struct block_rec *list;
+ struct slist_elm slist;
};
-static void slist_remove(struct recompiler *rec, struct block_rec *elm)
-{
- struct block_rec *prev;
-
- if (rec->list == elm) {
- rec->list = elm->next;
- } else {
- for (prev = rec->list; prev && prev->next != elm; )
- prev = prev->next;
- if (prev)
- prev->next = elm->next;
- }
-}
-
static void lightrec_compile_list(struct recompiler *rec)
{
- struct block_rec *next;
+ struct block_rec *block_rec;
+ struct slist_elm *next;
struct block *block;
int ret;
- while (!!(next = rec->list)) {
- block = next->block;
+ while (!!(next = slist_first(&rec->slist))) {
+ block_rec = container_of(next, struct block_rec, slist);
+ block = block_rec->block;
rec->current_block = block;
pthread_mutex_unlock(&rec->mutex);
@@ -72,9 +61,9 @@ static void lightrec_compile_list(struct recompiler *rec)
pthread_mutex_lock(&rec->mutex);
- slist_remove(rec, next);
+ slist_remove(&rec->slist, next);
lightrec_free(rec->state, MEM_FOR_LIGHTREC,
- sizeof(*next), next);
+ sizeof(*block_rec), block_rec);
pthread_cond_signal(&rec->cond);
}
@@ -87,19 +76,21 @@ static void * lightrec_recompiler_thd(void *d)
pthread_mutex_lock(&rec->mutex);
- for (;;) {
+ do {
do {
pthread_cond_wait(&rec->cond, &rec->mutex);
- if (rec->stop) {
- pthread_mutex_unlock(&rec->mutex);
- return NULL;
- }
+ if (rec->stop)
+ goto out_unlock;
- } while (!rec->list);
+ } while (slist_empty(&rec->slist));
lightrec_compile_list(rec);
- }
+ } while (!rec->stop);
+
+out_unlock:
+ pthread_mutex_unlock(&rec->mutex);
+ return NULL;
}
struct recompiler *lightrec_recompiler_init(struct lightrec_state *state)
@@ -116,7 +107,7 @@ struct recompiler *lightrec_recompiler_init(struct lightrec_state *state)
rec->state = state;
rec->stop = false;
rec->current_block = NULL;
- rec->list = NULL;
+ slist_init(&rec->slist);
ret = pthread_cond_init(&rec->cond, NULL);
if (ret) {
@@ -164,60 +155,77 @@ void lightrec_free_recompiler(struct recompiler *rec)
int lightrec_recompiler_add(struct recompiler *rec, struct block *block)
{
- struct block_rec *block_rec, *prev;
+ struct slist_elm *elm, *prev;
+ struct block_rec *block_rec;
+ int ret = 0;
pthread_mutex_lock(&rec->mutex);
- for (block_rec = rec->list, prev = NULL; block_rec;
- prev = block_rec, block_rec = block_rec->next) {
+ /* If the block is marked as dead, don't compile it, it will be removed
+ * as soon as it's safe. */
+ if (block->flags & BLOCK_IS_DEAD)
+ goto out_unlock;
+
+ for (elm = slist_first(&rec->slist), prev = NULL; elm;
+ prev = elm, elm = elm->next) {
+ block_rec = container_of(elm, struct block_rec, slist);
+
if (block_rec->block == block) {
/* The block to compile is already in the queue - bump
- * it to the top of the list */
- if (prev) {
- prev->next = block_rec->next;
- block_rec->next = rec->list;
- rec->list = block_rec;
+ * it to the top of the list, unless the block is being
+ * recompiled. */
+ if (prev && !(block->flags & BLOCK_SHOULD_RECOMPILE)) {
+ slist_remove_next(prev);
+ slist_append(&rec->slist, elm);
}
- pthread_mutex_unlock(&rec->mutex);
- return 0;
+ goto out_unlock;
}
}
/* By the time this function was called, the block has been recompiled
* and ins't in the wait list anymore. Just return here. */
- if (block->function) {
- pthread_mutex_unlock(&rec->mutex);
- return 0;
- }
+ if (block->function && !(block->flags & BLOCK_SHOULD_RECOMPILE))
+ goto out_unlock;
block_rec = lightrec_malloc(rec->state, MEM_FOR_LIGHTREC,
sizeof(*block_rec));
if (!block_rec) {
- pthread_mutex_unlock(&rec->mutex);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_unlock;
}
pr_debug("Adding block PC 0x%x to recompiler\n", block->pc);
block_rec->block = block;
- block_rec->next = rec->list;
- rec->list = block_rec;
+
+ elm = &rec->slist;
+
+ /* If the block is being recompiled, push it to the end of the queue;
+ * otherwise push it to the front of the queue. */
+ if (block->flags & BLOCK_SHOULD_RECOMPILE)
+ for (; elm->next; elm = elm->next);
+
+ slist_append(elm, &block_rec->slist);
/* Signal the thread */
pthread_cond_signal(&rec->cond);
- pthread_mutex_unlock(&rec->mutex);
- return 0;
+out_unlock:
+ pthread_mutex_unlock(&rec->mutex);
+ return ret;
}
void lightrec_recompiler_remove(struct recompiler *rec, struct block *block)
{
struct block_rec *block_rec;
+ struct slist_elm *elm;
pthread_mutex_lock(&rec->mutex);
- for (block_rec = rec->list; block_rec; block_rec = block_rec->next) {
+ for (elm = slist_first(&rec->slist); elm; elm = elm->next) {
+ block_rec = container_of(elm, struct block_rec, slist);
+
if (block_rec->block == block) {
if (block == rec->current_block) {
/* Block is being recompiled - wait for
@@ -229,7 +237,7 @@ void lightrec_recompiler_remove(struct recompiler *rec, struct block *block)
} else {
/* Block is not yet being processed - remove it
* from the list */
- slist_remove(rec, block_rec);
+ slist_remove(&rec->slist, elm);
lightrec_free(rec->state, MEM_FOR_LIGHTREC,
sizeof(*block_rec), block_rec);
}