Skip to content

Commit

Permalink
fix GC + union
Browse files Browse the repository at this point in the history
  • Loading branch information
marcj committed Jun 30, 2022
1 parent 1d82863 commit ba0a041
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 100 deletions.
36 changes: 28 additions & 8 deletions src/checker/vm2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,19 @@ namespace ts::vm2 {
gcQueueRef[gcQueueRefIdx++] = typeRef;
}

void gc(Type *type) {
inline void gcWithoutChildren(Type *type) {
if (gcQueueIdx>=maxGcSize) {
//garbage collect now
gcFlush();
}
// debug("gc ({}) {}", type->users, stringify(type));
if (type->users > 0) return;
gcQueue[gcQueueIdx++] = type;
}

void gc(Type *type) {
gcWithoutChildren(type);

switch (type->kind) {
case TypeKind::Union:
case TypeKind::Tuple:
Expand All @@ -69,7 +76,6 @@ namespace ts::vm2 {
break;
}
}
gcQueue[gcQueueIdx++] = type;
}

inline Type *use(Type *type) {
Expand Down Expand Up @@ -105,17 +111,23 @@ namespace ts::vm2 {
void drop(Type *type) {
if (type == nullptr) return;

// debug("drop({}) {}", stringify(type), type->users);
type->users--;
// debug("drop ({}) {}", type->users, stringify(type));
if (!type->users) {
gc(type);
}
}

void gcStackAndFlush() {
gcStack();
gcFlush();
}

void gcStack() {
for (unsigned int i = 0; i<sp; i++) {
gc(stack[i]);
}
sp = 0;
}

void clear(shared<ts::vm2::Module> &module) {
Expand Down Expand Up @@ -166,6 +178,10 @@ namespace ts::vm2 {
report(DiagnosticMessage(message, activeSubroutine->ip));
}

inline void report(const string &message, unsigned int ip) {
report(DiagnosticMessage(message, ip));
}

inline void pushFrame() {
auto next = frames.push(); ///&frames[frameIdx++];
//important to reset necessary stuff, since we reuse
Expand Down Expand Up @@ -427,6 +443,7 @@ namespace ts::vm2 {
case OP::Halt: {
// activeSubroutine = activeSubroutines.reset();
// frame = frames.reset();
// gcStack();
// gcFlush();
return;
}
Expand Down Expand Up @@ -545,7 +562,7 @@ namespace ts::vm2 {
push(types[0]);
} else {
auto result = allocate(TypeKind::Union);
TypeRef *current = useAsRef(types[0]);
TypeRef *current = (TypeRef *)(result->type = useAsRef(types[0]));
for_each(++types.begin(), types.end(), [&current](auto v) {
current->next = useAsRef(v);
current = current->next;
Expand Down Expand Up @@ -715,6 +732,7 @@ namespace ts::vm2 {
auto types = popFrame();
if (types.empty()) {
item->type = nullptr;
push(item);
break;
}

Expand All @@ -723,8 +741,9 @@ namespace ts::vm2 {
//if type has no owner, we can steal its children
if (type->users == 0) {
item->type = type->type;
item->type = nullptr;
//set current to the end of the list
type->type = nullptr;
//since we stole its children, we want it to GC but without its children. their 'users' count belongs now to us.
gcWithoutChildren(type);
} else {
throw std::runtime_error("Can not merge used union");
}
Expand All @@ -742,6 +761,8 @@ namespace ts::vm2 {
if (v->users == 0) {
current->next = (TypeRef *) v->type;
v->type = nullptr;
//since we stole its children, we want it to GC but without its children. their 'users' count belongs now to us.
gcWithoutChildren(v);
//set current to the end of the list
while (current->next) current = current->next;
} else {
Expand All @@ -753,8 +774,7 @@ namespace ts::vm2 {
}
});
current->next = nullptr;

stack[sp++] = item;
push(item);
break;
}
case OP::TupleMember: {
Expand Down
2 changes: 2 additions & 0 deletions src/checker/vm2.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ namespace ts::vm2 {
}

Type *next() {
if (!current) return nullptr;
auto t = current->type;
current = current->next;
return t;
Expand Down Expand Up @@ -157,6 +158,7 @@ namespace ts::vm2 {
void gc(Type *type);
// Garbage collect whatever is left on the stack
void gcStack();
void gcStackAndFlush();

std::span<Type *> popFrame();

Expand Down
103 changes: 11 additions & 92 deletions src/tests/test_vm2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,78 +15,6 @@ using namespace ts::vm2;
using std::string;
using std::string_view;

//struct StringLiteral {
// string_view text;
//};

//struct Type;
//
//struct PropertySignature {
// string_view name;
//// std::reference_wrapper<Type> type;
//};
//
//struct ObjectLiteral {
// string_view name;
// std::array<shared<Type>, 4> types;
//// std::vector<Type> types;
//};
//
//struct Type {
// unsigned int ip;
// TypeKind type = TypeKind::Unknown;
//
// union T {
// struct StringLiteral stringLiteral;
// struct PropertySignature propertySignature;
//// struct ObjectLiteral objectLiteral;
// };
//
// T v;
//};

template<class T>
struct Pool {
std::array<T, 300> pool;
unsigned int i{};

void clear() {
i = 0;
}

T *allocate() {
return &pool[i++];
}

// std::vector<T> pool;
// Pool () {
// pool.reserve(300);
// }
// T *make() {
// return &pool.emplace_back();
// }

// shared<T> make() {
// return std::make_shared<T>();
// }
};
//
//struct TypeMemoryPool {
// Pool<TypeNever> never;
// Pool<TypeAny> any;
// Pool<TypeLiteral> literal;
// Pool<TypeObjectLiteral> objectLiteral;
// Pool<TypePropertySignature> propertySignature;
//
// void clear() {
// never.clear();
// any.clear();
// literal.clear();
// objectLiteral.clear();
// propertySignature.clear();
// }
//};

TEST(bench, size) {
std::array<Type, 1> a1;
std::array<Type, 2> a2;
Expand All @@ -101,15 +29,6 @@ TEST(bench, size) {
debug("std::array<TypeBase, 4> = {}", sizeof(std::array<Type, 4>));
}

//TEST(vm2, reinterpret) {
// auto base = std::make_shared<Type>();
//// printKind(base);
// printKind(std::reinterpret_pointer_cast<TypeNever>(base));
// auto never = std::make_shared<TypeNever>();
// printKind(never);
//// printKind(std::reinterpret_pointer_cast<TypeBase>(never));
//}

TEST(vm2, vm2Base1) {
string code = R"(
const v1: string = "abc";
Expand All @@ -118,6 +37,9 @@ const v2: number = 123;
auto module = std::make_shared<vm2::Module>(ts::compile(code), "app.ts", "");
run(module);
EXPECT_EQ(module->errors.size(), 0);
ts::vm2::gcStackAndFlush();
//only v1, v2
EXPECT_EQ(ts::vm2::pool.active, 2);

ts::bench("first", 1000, [&] {
module->clear();
Expand All @@ -141,9 +63,9 @@ const v3: a<true> = false;
module->printErrors();

EXPECT_EQ(module->errors.size(), 1);
ts::vm2::gcFlush();
//only v1, v2, v3 cached value should live
EXPECT_EQ(ts::vm2::pool.active, 3);
ts::vm2::gcStackAndFlush();
//only v1, v2, v3 plus for each 4 union (true | string | number)
EXPECT_EQ(ts::vm2::pool.active, 3 * 4);

ts::bench("first", 1000, [&] {
ts::vm2::clear(module);
Expand All @@ -164,8 +86,8 @@ const v3: a<string> = 'nope';
module->printErrors();

EXPECT_EQ(module->errors.size(), 1);
ts::vm2::gcFlush();
//only v1, v2, v3, plus 'yes' : 'no' subroutine cached value should live
ts::vm2::gcStackAndFlush();
EXPECT_EQ(ts::vm2::pool.active, 5);

ts::bench("first", 1000, [&] {
Expand Down Expand Up @@ -222,7 +144,7 @@ const var1: a<string> = false;
EXPECT_EQ(ts::vm2::pool.active, 1);

ts::vm2::clear(module);
ts::vm2::gcFlush();
ts::vm2::gcStackAndFlush();
EXPECT_EQ(ts::vm2::pool.active, 0);

ts::bench("first", 1000, [&] {
Expand All @@ -246,8 +168,7 @@ TEST(vm2, gcUnion) {
auto module = std::make_shared<vm2::Module>(program.build(), "app.ts", "");
run(module);
EXPECT_EQ(module->errors.size(), 0);
ts::vm2::gcStack();
ts::vm2::gcFlush();
ts::vm2::gcStackAndFlush();
EXPECT_EQ(ts::vm2::pool.active, 0);
}

Expand All @@ -264,8 +185,7 @@ TEST(vm2, gcTuple) {
auto module = std::make_shared<vm2::Module>(program.build(), "app.ts", "");
run(module);
EXPECT_EQ(module->errors.size(), 0);
ts::vm2::gcStack();
ts::vm2::gcFlush();
ts::vm2::gcStackAndFlush();
EXPECT_EQ(ts::vm2::pool.active, 0);
}

Expand All @@ -285,8 +205,7 @@ TEST(vm2, gcObject) {
auto module = std::make_shared<vm2::Module>(program.build(), "app.ts", "");
run(module);
EXPECT_EQ(module->errors.size(), 0);
ts::vm2::gcStack();
ts::vm2::gcFlush();
ts::vm2::gcStackAndFlush();
EXPECT_EQ(ts::vm2::pool.active, 0);
}

Expand Down

0 comments on commit ba0a041

Please sign in to comment.