Как мне обработать объект, перемещающийся в памяти в середине метода?

Я пишу VM на C ++ для языка программирования. Язык является сборщиком мусора, поэтому у меня есть экземпляры классов C ++, которые размещены в куче сборщика мусора. Я использую копирующий коллектор, поэтому, когда происходит сборщик мусора, эти объекты перемещаются в память. Это означает, что каждый указатель на этот объект должен быть обновлен. Наиболее из этих указателей легко работать, кроме одного хитрого: this, Рассматривать:

class SomeObj : public Managed      // inheriting from this means it's on the GC heap
{
public:
void method()
{
SomeObj* other = new SomeObj(); // could trigger a GC.
printf("%d\n", someField);      // this points to wrong memory
}

private:
int someField;
};

Если я нахожусь в середине метода экземпляра некоторого объекта, который живет в куче GC, то this указывает на некоторую память GC. Коллекция может происходить в середине этого метода. Когда это происходит, объект перемещается в новое место. Но, поскольку мы находимся в середине вызова метода, this все еще указывает на старое неправильное местоположение.

Я мог бы обойти это, не используя методы экземпляров в классах, находящихся в управляемой памяти, но мне нравится, что код проще в этом смысле. Есть ли какие-то методы для борьбы с этим?

2

Решение

Ваш GC должен сканировать стек и регистрирует указатели и исправляет их. Если ваша виртуальная машина поддерживает многопоточность, вам нужно приостановить все потоки при сканировании их стеков. Указатель this будет находиться в стеке или в регистре.

Поскольку C ++ не предоставляет информацию о типе стека, вам может быть трудно что-то вроде

int i = 1000000;
char * p = new char[10]; // 0xF4240 = 1000000

Какой бы метод вы ни использовали для перемещения других указателей, у вас будет такая же проблема. В какой-то момент ваш код должен конвертировать дескрипторы в указатели, и эти указатели необходимо будет исправить.

Измените код C ++ следующим образом

func()->method()

выглядеть как

struct GCroot call123 = { func() };
call123.obj->method();

Многопоточность. Если у вас есть такой код

struct GCroot obj123 = { /* .. */ };
obj123.ptr->x = obj123.ptr->x + 1;

это может генерировать псевдо-ассемблерный код, как это

load r1, obj123.ptr
load r2, (r1)
add r2, 1
store (r1), r2

если другой поток выполняет GC в любое время между первой и последней строками asm, как исправить r1?

2

Другие решения

Вы можете ввести другой уровень косвенности. Я буду использовать ваш пример:

class SomeData : public Managed
{
int someField;
};

class SomeObj : public Managed      // inheriting from this means it's on the GC heap
{
public:
void method()
{
SomeObj* other = new SomeObj(); // could trigger a GC.
printf("%d\n", someData->someField);      // this points to wrong memory
}

private:
SomeObjData* someData;
};

Обратите внимание, что каждая реализация управляемого будет делать это.

1

По вопросам рекламы [email protected]