Scripting: Allow weakrefs to be marked for auto-collection

This commit is contained in:
Vicki Pfau 2023-01-26 03:29:55 -08:00
parent 58089fb334
commit b5f600c0c5
4 changed files with 120 additions and 5 deletions

View File

@ -89,6 +89,7 @@ uint32_t mScriptContextSetWeakref(struct mScriptContext*, struct mScriptValue* v
struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value); struct mScriptValue* mScriptContextMakeWeakref(struct mScriptContext*, struct mScriptValue* value);
struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value); struct mScriptValue* mScriptContextAccessWeakref(struct mScriptContext*, struct mScriptValue* value);
void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref); void mScriptContextClearWeakref(struct mScriptContext*, uint32_t weakref);
void mScriptContextDisownWeakref(struct mScriptContext*, uint32_t weakref);
void mScriptContextAttachStdlib(struct mScriptContext* context); void mScriptContextAttachStdlib(struct mScriptContext* context);
void mScriptContextAttachSocket(struct mScriptContext* context); void mScriptContextAttachSocket(struct mScriptContext* context);

View File

@ -12,8 +12,9 @@ set(TEST_FILES
if(USE_LUA) if(USE_LUA)
list(APPEND SOURCE_FILES engines/lua.c) list(APPEND SOURCE_FILES engines/lua.c)
list(APPEND TEST_FILES list(APPEND TEST_FILES
test/stdlib.c test/context.c
test/lua.c) test/lua.c
test/stdlib.c)
endif() endif()
source_group("Scripting" FILES ${SOURCE_FILES}) source_group("Scripting" FILES ${SOURCE_FILES})

View File

@ -71,8 +71,8 @@ void mScriptContextInit(struct mScriptContext* context) {
void mScriptContextDeinit(struct mScriptContext* context) { void mScriptContextDeinit(struct mScriptContext* context) {
HashTableDeinit(&context->rootScope); HashTableDeinit(&context->rootScope);
HashTableDeinit(&context->weakrefs);
mScriptContextDrainPool(context); mScriptContextDrainPool(context);
HashTableDeinit(&context->weakrefs);
mScriptListDeinit(&context->refPool); mScriptListDeinit(&context->refPool);
HashTableDeinit(&context->callbacks); HashTableDeinit(&context->callbacks);
TableDeinit(&context->callbackId); TableDeinit(&context->callbackId);
@ -102,9 +102,12 @@ void mScriptContextFillPool(struct mScriptContext* context, struct mScriptValue*
void mScriptContextDrainPool(struct mScriptContext* context) { void mScriptContextDrainPool(struct mScriptContext* context) {
size_t i; size_t i;
for (i = 0; i < mScriptListSize(&context->refPool); ++i) { for (i = 0; i < mScriptListSize(&context->refPool); ++i) {
struct mScriptValue* value = mScriptValueUnwrap(mScriptListGetPointer(&context->refPool, i)); struct mScriptValue* value = mScriptListGetPointer(&context->refPool, i);
if (value) { if (value->type->base == mSCRIPT_TYPE_WRAPPER) {
value = mScriptValueUnwrap(value);
mScriptValueDeref(value); mScriptValueDeref(value);
} else if (value->type == mSCRIPT_TYPE_MS_WEAKREF) {
mScriptContextClearWeakref(context, value->value.u32);
} }
} }
mScriptListClear(&context->refPool); mScriptListClear(&context->refPool);
@ -201,6 +204,13 @@ void mScriptContextClearWeakref(struct mScriptContext* context, uint32_t weakref
TableRemove(&context->weakrefs, weakref); TableRemove(&context->weakrefs, weakref);
} }
void mScriptContextDisownWeakref(struct mScriptContext* context, uint32_t weakref) {
struct mScriptValue* poolEntry = mScriptListAppend(&context->refPool);
poolEntry->type = mSCRIPT_TYPE_MS_WEAKREF;
poolEntry->value.u32 = weakref;
poolEntry->refs = mSCRIPT_VALUE_UNREF;
}
void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback) { void mScriptContextTriggerCallback(struct mScriptContext* context, const char* callback) {
struct mScriptValue* list = HashTableLookup(&context->callbacks, callback); struct mScriptValue* list = HashTableLookup(&context->callbacks, callback);
if (!list) { if (!list) {

103
src/script/test/context.c Normal file
View File

@ -0,0 +1,103 @@
/* Copyright (c) 2013-2023 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/test/suite.h"
#include <mgba/script/context.h>
#include <mgba/script/macros.h>
#include <mgba/script/types.h>
M_TEST_DEFINE(weakrefBasic) {
struct mScriptContext context;
mScriptContextInit(&context);
struct mScriptValue weakref = mSCRIPT_VAL(WEAKREF, 1);
struct mScriptValue fakeVal = mSCRIPT_S32(0x7E57CA5E);
struct mScriptValue* val;
assert_int_equal(TableSize(&context.weakrefs), 0);
assert_null(TableLookup(&context.weakrefs, 1));
assert_int_equal(context.nextWeakref, 1);
assert_null(mScriptContextAccessWeakref(&context, &weakref));
assert_int_equal(mScriptContextSetWeakref(&context, &fakeVal), 1);
assert_int_equal(context.nextWeakref, 2);
assert_int_equal(TableSize(&context.weakrefs), 1);
val = mScriptContextAccessWeakref(&context, &weakref);
assert_non_null(val);
assert_int_equal(val->value.u32, 0x7E57CA5E);
mScriptContextClearWeakref(&context, 1);
assert_int_equal(TableSize(&context.weakrefs), 0);
assert_null(TableLookup(&context.weakrefs, 1));
assert_int_equal(context.nextWeakref, 2);
assert_null(mScriptContextAccessWeakref(&context, &weakref));
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(drainPool) {
struct mScriptContext context;
mScriptContextInit(&context);
assert_int_equal(mScriptListSize(&context.refPool), 0);
struct mScriptValue fakeVal = mSCRIPT_CHARP("foo");
fakeVal.refs = 2;
mScriptContextFillPool(&context, &fakeVal);
assert_int_equal(mScriptListSize(&context.refPool), 1);
assert_int_equal(fakeVal.refs, 2);
mScriptContextDrainPool(&context);
assert_int_equal(mScriptListSize(&context.refPool), 0);
assert_int_equal(fakeVal.refs, 1);
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(disownWeakref) {
struct mScriptContext context;
mScriptContextInit(&context);
struct mScriptValue weakref = mSCRIPT_VAL(WEAKREF, 1);
struct mScriptValue fakeVal = mSCRIPT_S32(0x7E57CA5E);
struct mScriptValue* val;
assert_int_equal(mScriptListSize(&context.refPool), 0);
assert_int_equal(TableSize(&context.weakrefs), 0);
assert_null(TableLookup(&context.weakrefs, 1));
assert_int_equal(context.nextWeakref, 1);
assert_null(mScriptContextAccessWeakref(&context, &weakref));
assert_int_equal(mScriptContextSetWeakref(&context, &fakeVal), 1);
assert_int_equal(TableSize(&context.weakrefs), 1);
assert_int_equal(context.nextWeakref, 2);
val = mScriptContextAccessWeakref(&context, &weakref);
assert_non_null(val);
assert_int_equal(val->value.u32, 0x7E57CA5E);
mScriptContextDisownWeakref(&context, 1);
assert_int_equal(mScriptListSize(&context.refPool), 1);
assert_int_equal(TableSize(&context.weakrefs), 1);
val = mScriptContextAccessWeakref(&context, &weakref);
assert_non_null(val);
assert_int_equal(val->value.u32, 0x7E57CA5E);
mScriptContextDrainPool(&context);
assert_int_equal(mScriptListSize(&context.refPool), 0);
assert_int_equal(TableSize(&context.weakrefs), 0);
assert_null(TableLookup(&context.weakrefs, 1));
assert_null(mScriptContextAccessWeakref(&context, &weakref));
mScriptContextDeinit(&context);
}
M_TEST_SUITE_DEFINE(mScript,
cmocka_unit_test(weakrefBasic),
cmocka_unit_test(drainPool),
cmocka_unit_test(disownWeakref),
)