Tracking globals (#4542)
This commit is contained in:
committed by
Stanislav Erokhin
parent
66de5dceb9
commit
2057e5c8f1
@@ -25,8 +25,9 @@ void ensureUsed(Ret (*f)(Args...)) {
|
||||
void EnsureDeclarationsEmitted() {
|
||||
ensureUsed(AllocInstance);
|
||||
ensureUsed(AllocArrayInstance);
|
||||
ensureUsed(InitInstance);
|
||||
ensureUsed(InitSharedInstance);
|
||||
ensureUsed(InitThreadLocalSingleton);
|
||||
ensureUsed(InitSingleton);
|
||||
ensureUsed(InitAndRegisterGlobal);
|
||||
ensureUsed(UpdateHeapRef);
|
||||
ensureUsed(UpdateStackRef);
|
||||
ensureUsed(UpdateReturnRef);
|
||||
|
||||
@@ -142,11 +142,14 @@ OBJ_GETTER(AllocInstance, const TypeInfo* type_info) RUNTIME_NOTHROW;
|
||||
|
||||
OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements);
|
||||
|
||||
OBJ_GETTER(InitInstance,
|
||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||
|
||||
OBJ_GETTER(InitSharedInstance,
|
||||
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||
OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
|
||||
|
||||
// `initialValue` may be `nullptr`, which signifies that the appropriate initial value was already
|
||||
// set by static initialization.
|
||||
// TODO: When global initialization becomes lazy, this signature won't do.
|
||||
void InitAndRegisterGlobal(ObjHeader** location, const ObjHeader* initialValue) RUNTIME_NOTHROW;
|
||||
|
||||
//
|
||||
// Object reference management.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef RUNTIME_MULTI_SOURCE_QUEUE_H
|
||||
#define RUNTIME_MULTI_SOURCE_QUEUE_H
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace kotlin {
|
||||
|
||||
// A queue that is constructed by collecting subqueues from several `Producer`s.
|
||||
template <typename T>
|
||||
class MultiSourceQueue {
|
||||
public:
|
||||
class Producer {
|
||||
public:
|
||||
void Insert(const T& value) noexcept { queue_.push_back(value); }
|
||||
|
||||
private:
|
||||
friend class MultiSourceQueue;
|
||||
|
||||
std::list<T> queue_;
|
||||
};
|
||||
|
||||
using Iterator = typename std::list<T>::iterator;
|
||||
|
||||
Iterator begin() noexcept { return commonQueue_.begin(); }
|
||||
Iterator end() noexcept { return commonQueue_.end(); }
|
||||
|
||||
// Merge `producer`s queue with `this`. `producer` will have empty queue after the call.
|
||||
// This call is performed without heap allocations. TODO: Test that no allocations are happening.
|
||||
void Collect(Producer* producer) noexcept { commonQueue_.splice(commonQueue_.end(), producer->queue_); }
|
||||
|
||||
private:
|
||||
// Using `std::list` as it allows to implement `Collect` without memory allocations,
|
||||
// which is important for GC mark phase.
|
||||
std::list<T> commonQueue_;
|
||||
};
|
||||
|
||||
} // namespace kotlin
|
||||
|
||||
#endif // RUNTIME_MULTI_SOURCE_QUEUE_H
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "MultiSourceQueue.hpp"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace kotlin;
|
||||
|
||||
using IntQueue = MultiSourceQueue<int>;
|
||||
|
||||
TEST(MultiSourceQueueTest, Empty) {
|
||||
IntQueue queue;
|
||||
|
||||
std::vector<int> actual;
|
||||
for (int element : queue) {
|
||||
actual.push_back(element);
|
||||
}
|
||||
|
||||
EXPECT_THAT(actual, testing::IsEmpty());
|
||||
}
|
||||
|
||||
TEST(MultiSourceQueueTest, DoNotCollect) {
|
||||
IntQueue queue;
|
||||
IntQueue::Producer producer;
|
||||
|
||||
producer.Insert(1);
|
||||
producer.Insert(2);
|
||||
|
||||
std::vector<int> actual;
|
||||
for (int element : queue) {
|
||||
actual.push_back(element);
|
||||
}
|
||||
|
||||
EXPECT_THAT(actual, testing::IsEmpty());
|
||||
}
|
||||
|
||||
TEST(MultiSourceQueueTest, Collect) {
|
||||
IntQueue queue;
|
||||
IntQueue::Producer producer1;
|
||||
IntQueue::Producer producer2;
|
||||
|
||||
producer1.Insert(1);
|
||||
producer1.Insert(2);
|
||||
producer2.Insert(10);
|
||||
producer2.Insert(20);
|
||||
|
||||
queue.Collect(&producer1);
|
||||
queue.Collect(&producer2);
|
||||
|
||||
std::vector<int> actual;
|
||||
for (int element : queue) {
|
||||
actual.push_back(element);
|
||||
}
|
||||
|
||||
EXPECT_THAT(actual, testing::ElementsAre(1, 2, 10, 20));
|
||||
}
|
||||
|
||||
TEST(MultiSourceQueueTest, CollectSeveralTimes) {
|
||||
IntQueue queue;
|
||||
IntQueue::Producer producer;
|
||||
|
||||
// Add 2 elements and collect.
|
||||
producer.Insert(1);
|
||||
producer.Insert(2);
|
||||
queue.Collect(&producer);
|
||||
|
||||
// Add another element and collect.
|
||||
producer.Insert(3);
|
||||
queue.Collect(&producer);
|
||||
|
||||
// Collect without adding elements.
|
||||
queue.Collect(&producer);
|
||||
|
||||
// Add yet another two elements and collect.
|
||||
producer.Insert(4);
|
||||
producer.Insert(5);
|
||||
queue.Collect(&producer);
|
||||
|
||||
std::vector<int> actual;
|
||||
for (int element : queue) {
|
||||
actual.push_back(element);
|
||||
}
|
||||
|
||||
EXPECT_THAT(actual, testing::ElementsAre(1, 2, 3, 4, 5));
|
||||
}
|
||||
Reference in New Issue
Block a user