[K/N] Rework object and enum classes initialization

Now it works with common logic for all static scope not with custom one.
This commit is contained in:
Pavel Kunyavskiy
2022-11-01 17:29:13 +01:00
committed by Space Team
parent 7006eb938d
commit d3adfec2fb
38 changed files with 393 additions and 1050 deletions
@@ -31,8 +31,6 @@ touchType(KRefSharedHolder)
touchFunction(AllocInstance)
touchFunction(AllocArrayInstance)
touchFunction(InitThreadLocalSingleton)
touchFunction(InitSingleton)
touchFunction(InitAndRegisterGlobal)
touchFunction(UpdateHeapRef)
touchFunction(UpdateStackRef)
@@ -2373,104 +2373,6 @@ OBJ_GETTER(allocArrayInstance, const TypeInfo* type_info, int32_t elements) {
RETURN_OBJ(container.GetPlace()->obj());
}
template <bool Strict>
OBJ_GETTER(initThreadLocalSingleton,
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
ObjHeader* value = *location;
if (value != nullptr) {
// OK'ish, inited by someone else.
RETURN_OBJ(value);
}
ObjHeader* object = allocInstance<Strict>(typeInfo, OBJ_RESULT);
updateHeapRef<Strict>(location, object);
#if KONAN_NO_EXCEPTIONS
ctor(object);
return object;
#else
try {
ctor(object);
return object;
} catch (...) {
UpdateReturnRef(OBJ_RESULT, nullptr);
ZeroHeapRef(location);
throw;
}
#endif
}
template <bool Strict>
OBJ_GETTER(initSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
#if KONAN_NO_THREADS
ObjHeader* value = *location;
if (value != nullptr) {
// OK'ish, inited by someone else.
RETURN_OBJ(value);
}
ObjHeader* object = AllocInstance(typeInfo, OBJ_RESULT);
UpdateHeapRef(location, object);
#if KONAN_NO_EXCEPTIONS
ctor(object);
FreezeSubgraph(object);
return object;
#else
try {
ctor(object);
if (Strict)
FreezeSubgraph(object);
return object;
} catch (...) {
UpdateReturnRef(OBJ_RESULT, nullptr);
ZeroHeapRef(location);
throw;
}
#endif // KONAN_NO_EXCEPTIONS
#else // KONAN_NO_THREADS
// Search from the top of the stack.
for (auto it = memoryState->initializingSingletons.rbegin(); it != memoryState->initializingSingletons.rend(); ++it) {
if (it->first == location) {
RETURN_OBJ(it->second);
}
}
ObjHeader* initializing = kInitializingSingleton;
// Spin lock.
ObjHeader* value = nullptr;
while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing);
if (value != nullptr) {
// OK'ish, inited by someone else.
RETURN_OBJ(value);
}
ObjHeader* object = AllocInstance(typeInfo, OBJ_RESULT);
memoryState->initializingSingletons.push_back(std::make_pair(location, object));
#if KONAN_NO_EXCEPTIONS
ctor(object);
if (Strict)
FreezeSubgraph(object);
UpdateHeapRef(location, object);
synchronize();
memoryState->initializingSingletons.pop_back();
return object;
#else // KONAN_NO_EXCEPTIONS
try {
ctor(object);
if (Strict)
FreezeSubgraph(object);
UpdateHeapRef(location, object);
synchronize();
memoryState->initializingSingletons.pop_back();
return object;
} catch (...) {
UpdateReturnRef(OBJ_RESULT, nullptr);
zeroHeapRef(location);
memoryState->initializingSingletons.pop_back();
synchronize();
throw;
}
#endif // KONAN_NO_EXCEPTIONS
#endif // KONAN_NO_THREADS
}
/**
* We keep thread affinity and reference value based cookie in the atomic references, so that
* repeating read operation of the same value do not lead to the repeating rememberNewContainer() operation.
@@ -3398,20 +3300,6 @@ OBJ_GETTER(AllocArrayInstanceRelaxed, const TypeInfo* typeInfo, int32_t elements
RETURN_RESULT_OF(allocArrayInstance<false>, typeInfo, elements);
}
OBJ_GETTER(InitThreadLocalSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(initThreadLocalSingleton<true>, location, typeInfo, ctor);
}
OBJ_GETTER(InitThreadLocalSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(initThreadLocalSingleton<false>, location, typeInfo, ctor);
}
OBJ_GETTER(InitSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(initSingleton<true>, location, typeInfo, ctor);
}
OBJ_GETTER(InitSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(initSingleton<false>, location, typeInfo, ctor);
}
void RUNTIME_NOTHROW InitAndRegisterGlobal(ObjHeader** location, const ObjHeader* initialValue) {
RuntimeCheck(false, "Global registration is impossible in legacy MM");
}
@@ -309,11 +309,6 @@ OBJ_GETTER(AllocInstanceRelaxed, const TypeInfo* type_info) RUNTIME_NOTHROW;
OBJ_GETTER(AllocArrayInstanceStrict, const TypeInfo* type_info, int32_t elements);
OBJ_GETTER(AllocArrayInstanceRelaxed, const TypeInfo* type_info, int32_t elements);
OBJ_GETTER(InitThreadLocalSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
OBJ_GETTER(InitThreadLocalSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
OBJ_GETTER(InitSingletonStrict, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
OBJ_GETTER(InitSingletonRelaxed, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
MODEL_VARIANTS(void, SetStackRef, ObjHeader** location, const ObjHeader* object);
MODEL_VARIANTS(void, SetHeapRef, ObjHeader** location, const ObjHeader* object);
@@ -25,8 +25,6 @@ void ensureUsed(Ret (*f)(Args...)) {
void EnsureDeclarationsEmitted() {
ensureUsed(AllocInstance);
ensureUsed(AllocArrayInstance);
ensureUsed(InitThreadLocalSingleton);
ensureUsed(InitSingleton);
ensureUsed(InitAndRegisterGlobal);
ensureUsed(UpdateHeapRef);
ensureUsed(UpdateStackRef);
@@ -83,6 +83,7 @@ void VLog(Level level, std::initializer_list<const char*> tags, const char* form
inline constexpr const char* kTagGC = "gc";
inline constexpr const char* kTagMM = "mm";
inline constexpr const char* kTagTLS = "tls";
} // namespace kotlin
@@ -195,9 +195,6 @@ OBJ_GETTER(AllocInstance, const TypeInfo* type_info) RUNTIME_NOTHROW;
OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements);
OBJ_GETTER(InitThreadLocalSingleton, 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.
@@ -53,6 +53,7 @@ class IntrinsicType {
const val IMMUTABLE_BLOB = "IMMUTABLE_BLOB"
const val INIT_INSTANCE = "INIT_INSTANCE"
const val IS_EXPERIMENTAL_MM = "IS_EXPERIMENTAL_MM"
const val THE_UNIT_INSTANCE = "THE_UNIT_INSTANCE"
// Enums
const val ENUM_VALUES = "ENUM_VALUES"
@@ -30,3 +30,6 @@ import kotlin.native.internal.IntrinsicType
// Reinterprets this value from T to R having the same binary representation (e.g. to unwrap inline class).
@TypedIntrinsic(IntrinsicType.IDENTITY) @PublishedApi external internal fun <T, R> T.reinterpret(): R
@TypedIntrinsic(IntrinsicType.THE_UNIT_INSTANCE) @ExportForCompiler external internal fun theUnitInstance(): Unit
@@ -1,80 +0,0 @@
/*
* Copyright 2010-2021 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 "InitializationScheme.hpp"
#include "Common.h"
#include "ObjectOps.hpp"
#include "ThreadData.hpp"
#include "ThreadState.hpp"
using namespace kotlin;
OBJ_GETTER(mm::InitThreadLocalSingleton, ThreadData* threadData, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
AssertThreadState(threadData, ThreadState::kRunnable);
if (auto* value = *location) {
// Initialized by someone else.
RETURN_OBJ(value);
}
auto* value = mm::AllocateObject(threadData, typeInfo, OBJ_RESULT);
mm::SetHeapRef(location, value);
#if KONAN_NO_EXCEPTIONS
ctor(value);
#else
try {
ctor(value);
} catch (...) {
mm::SetStackRef(OBJ_RESULT, nullptr);
mm::SetHeapRef(location, nullptr);
throw;
}
#endif
return value;
}
OBJ_GETTER(mm::InitSingleton, ThreadData* threadData, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
AssertThreadState(threadData, ThreadState::kRunnable);
auto& initializingSingletons = threadData->initializingSingletons();
// Search from the top of the stack.
for (auto it = initializingSingletons.rbegin(); it != initializingSingletons.rend(); ++it) {
if (it->first == location) {
RETURN_OBJ(it->second);
}
}
ObjHeader* initializing = kInitializingSingleton;
// Spin lock.
ObjHeader* value = nullptr;
{
ThreadStateGuard guard(ThreadState::kNative);
while ((value = __sync_val_compare_and_swap(location, nullptr, initializing)) == initializing) {
}
}
if (value != nullptr) {
// Initialized by someone else.
RETURN_OBJ(value);
}
auto* object = mm::AllocateObject(threadData, typeInfo, OBJ_RESULT);
initializingSingletons.push_back(std::make_pair(location, object));
#if KONAN_NO_EXCEPTIONS
ctor(object);
#else
try {
ctor(object);
} catch (...) {
mm::SetStackRef(OBJ_RESULT, nullptr);
mm::SetHeapRefAtomic(location, nullptr);
initializingSingletons.pop_back();
throw;
}
#endif
mm::GlobalsRegistry::Instance().RegisterStorageForGlobal(threadData, location);
mm::SetHeapRefAtomic(location, object);
initializingSingletons.pop_back();
return object;
}
@@ -1,22 +0,0 @@
/*
* Copyright 2010-2021 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_MM_INITIALIZATION_SCHEME_H
#define RUNTIME_MM_INITIALIZATION_SCHEME_H
#include "Memory.h"
namespace kotlin {
namespace mm {
class ThreadData;
OBJ_GETTER(InitThreadLocalSingleton, ThreadData* threadData, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
OBJ_GETTER(InitSingleton, ThreadData* threadData, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
} // namespace mm
} // namespace kotlin
#endif // RUNTIME_MM_INITIALIZATION_SCHEME_H
@@ -1,270 +0,0 @@
/*
* Copyright 2010-2021 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 "InitializationScheme.hpp"
#include <atomic>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "ObjectTestSupport.hpp"
#include "ScopedThread.hpp"
#include "TestSupport.hpp"
#include "ThreadData.hpp"
#include "Types.h"
#include "std_support/Vector.hpp"
using namespace kotlin;
using testing::_;
namespace {
struct EmptyPayload {
using Field = ObjHeader* EmptyPayload::*;
static constexpr std::array<Field, 0> kFields{};
};
class InitSingletonTest : public testing::Test {
public:
InitSingletonTest() {
globalConstructor_ = &constructor_;
}
~InitSingletonTest() {
globalConstructor_ = nullptr;
mm::GlobalData::Instance().gc().ClearForTests();
mm::GlobalData::Instance().globalsRegistry().ClearForTests();
}
testing::MockFunction<void(ObjHeader*)>& constructor() { return constructor_; }
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, mm::ThreadData& threadData) {
RETURN_RESULT_OF(mm::InitThreadLocalSingleton, &threadData, location, type_.typeInfo(), constructorImpl);
}
OBJ_GETTER(InitSingleton, ObjHeader** location, mm::ThreadData& threadData) {
RETURN_RESULT_OF(mm::InitSingleton, &threadData, location, type_.typeInfo(), constructorImpl);
}
private:
testing::StrictMock<testing::MockFunction<void(ObjHeader*)>> constructor_;
test_support::TypeInfoHolder type_{test_support::TypeInfoHolder::ObjectBuilder<EmptyPayload>()};
static testing::MockFunction<void(ObjHeader*)>* globalConstructor_;
static void constructorImpl(ObjHeader* object) { globalConstructor_->Call(object); }
};
// static
testing::MockFunction<void(ObjHeader*)>* InitSingletonTest::globalConstructor_ = nullptr;
} // namespace
TEST_F(InitSingletonTest, InitThreadLocalSingleton) {
RunInNewThread([this](mm::ThreadData& threadData) {
ObjHeader* location = nullptr;
ObjHeader* stackLocation = nullptr;
ObjHeader* valueAtConstructor = nullptr;
EXPECT_CALL(constructor(), Call(_)).WillOnce(
[&location, &stackLocation, &valueAtConstructor](ObjHeader* value) {
EXPECT_THAT(value, stackLocation);
EXPECT_THAT(value, location);
valueAtConstructor = value;
});
ObjHeader* value = InitThreadLocalSingleton(&location, threadData, &stackLocation);
EXPECT_THAT(value, stackLocation);
EXPECT_THAT(value, location);
EXPECT_THAT(valueAtConstructor, location);
});
}
TEST_F(InitSingletonTest, InitThreadLocalSingletonTwice) {
RunInNewThread([this](mm::ThreadData& threadData) {
ObjHeader previousValue;
ObjHeader* location = &previousValue;
ObjHeader* stackLocation = nullptr;
EXPECT_CALL(constructor(), Call(_)).Times(0);
ObjHeader* value = InitThreadLocalSingleton(&location, threadData, &stackLocation);
EXPECT_THAT(value, stackLocation);
EXPECT_THAT(value, location);
EXPECT_THAT(value, &previousValue);
});
}
TEST_F(InitSingletonTest, InitThreadLocalSingletonFail) {
RunInNewThread([this](mm::ThreadData& threadData) {
ObjHeader* location = nullptr;
ObjHeader* stackLocation = nullptr;
constexpr int kException = 42;
EXPECT_CALL(constructor(), Call(_)).WillOnce([]() { throw kException; });
try {
InitThreadLocalSingleton(&location, threadData, &stackLocation);
ASSERT_TRUE(false); // Cannot be reached.
} catch (int exception) {
EXPECT_THAT(exception, kException);
}
EXPECT_THAT(stackLocation, nullptr);
EXPECT_THAT(location, nullptr);
});
}
TEST_F(InitSingletonTest, InitSingleton) {
RunInNewThread([this](mm::ThreadData& threadData) {
ObjHeader* location = nullptr;
ObjHeader* stackLocation = nullptr;
ObjHeader* valueAtConstructor = nullptr;
EXPECT_CALL(constructor(), Call(_)).WillOnce(
[&location, &stackLocation, &valueAtConstructor](ObjHeader* value) {
EXPECT_THAT(value, stackLocation);
EXPECT_THAT(location, kInitializingSingleton);
valueAtConstructor = value;
});
ObjHeader* value = InitSingleton(&location, threadData, &stackLocation);
EXPECT_THAT(value, stackLocation);
EXPECT_THAT(value, location);
EXPECT_THAT(valueAtConstructor, location);
});
}
TEST_F(InitSingletonTest, InitSingletonTwice) {
RunInNewThread([this](mm::ThreadData& threadData) {
ObjHeader previousValue;
ObjHeader* location = &previousValue;
ObjHeader* stackLocation = nullptr;
EXPECT_CALL(constructor(), Call(_)).Times(0);
ObjHeader* value = InitSingleton(&location, threadData, &stackLocation);
EXPECT_THAT(value, stackLocation);
EXPECT_THAT(value, location);
EXPECT_THAT(value, &previousValue);
});
}
TEST_F(InitSingletonTest, InitSingletonFail) {
RunInNewThread([this](mm::ThreadData& threadData) {
ObjHeader* location = nullptr;
ObjHeader* stackLocation = nullptr;
constexpr int kException = 42;
EXPECT_CALL(constructor(), Call(_)).WillOnce([]() { throw kException; });
try {
InitSingleton(&location, threadData, &stackLocation);
ASSERT_TRUE(false); // Cannot be reached.
} catch (int exception) {
EXPECT_THAT(exception, kException);
}
EXPECT_THAT(stackLocation, nullptr);
EXPECT_THAT(location, nullptr);
});
}
TEST_F(InitSingletonTest, InitSingletonRecursive) {
RunInNewThread([this](mm::ThreadData& threadData) {
// The first singleton. Its constructor depends on the second singleton.
ObjHeader* location1 = nullptr;
ObjHeader* stackLocation1 = nullptr;
// The second singleton. Its constructor depends on the first singleton.
ObjHeader* location2 = nullptr;
ObjHeader* stackLocation2 = nullptr;
EXPECT_CALL(constructor(), Call(_))
.Times(2) // called only once for each singleton.
.WillRepeatedly([this, &location1, &stackLocation1, &location2, &stackLocation2, &threadData](ObjHeader* value) {
if (value == stackLocation1) {
ObjHeader* result = InitSingleton(&location2, threadData, &stackLocation2);
EXPECT_THAT(result, stackLocation2);
EXPECT_THAT(result, location2);
EXPECT_THAT(result, testing::Not(testing::Truly(isNullOrMarker)));
} else {
ObjHeader* result = InitSingleton(&location1, threadData, &stackLocation1);
EXPECT_THAT(result, stackLocation1);
EXPECT_THAT(result, testing::Ne(location1));
EXPECT_THAT(location1, kInitializingSingleton);
}
});
ObjHeader* value = InitSingleton(&location1, threadData, &stackLocation1);
EXPECT_THAT(value, stackLocation1);
EXPECT_THAT(value, location1);
});
}
TEST_F(InitSingletonTest, InitSingletonConcurrent) {
constexpr size_t kThreadCount = kDefaultThreadCount;
std::atomic<bool> canStart(false);
std::atomic<size_t> readyCount(0);
std_support::vector<ScopedThread> threads;
ObjHeader* location = nullptr;
std_support::vector<ObjHeader*> stackLocations(kThreadCount, nullptr);
std_support::vector<ObjHeader*> actual(kThreadCount, nullptr);
for (size_t i = 0; i < kThreadCount; ++i) {
threads.emplace_back([this, i, &location, &stackLocations, &actual, &readyCount, &canStart]() {
ScopedMemoryInit init;
auto* threadData = init.memoryState()->GetThreadData();
++readyCount;
while (!canStart) {
}
actual[i] = InitSingleton(&location, *threadData, &stackLocations[i]);
threadData->Publish();
});
}
while (readyCount < kThreadCount) {
}
// Constructor is called exactly once.
EXPECT_CALL(constructor(), Call(_));
canStart = true;
threads.clear();
testing::Mock::VerifyAndClearExpectations(&constructor());
EXPECT_THAT(location, testing::Not(testing::Truly(isNullOrMarker)));
EXPECT_THAT(stackLocations, testing::Each(location));
EXPECT_THAT(actual, testing::Each(location));
}
TEST_F(InitSingletonTest, InitSingletonConcurrentFailing) {
constexpr size_t kThreadCount = kDefaultThreadCount;
std::atomic<bool> canStart(false);
std::atomic<size_t> readyCount(0);
std_support::vector<ScopedThread> threads;
constexpr int kException = 42;
ObjHeader* location = nullptr;
std_support::vector<ObjHeader*> stackLocations(kThreadCount, nullptr);
for (size_t i = 0; i < kThreadCount; ++i) {
threads.emplace_back([this, i, &location, &stackLocations, &readyCount, &canStart]() {
ScopedMemoryInit init;
auto* threadData = init.memoryState()->GetThreadData();
++readyCount;
while (!canStart) {
}
try {
InitSingleton(&location, *threadData, &stackLocations[i]);
ASSERT_TRUE(false); // Cannot be reached.
} catch (int exception) {
EXPECT_THAT(exception, kException);
}
threadData->Publish();
});
}
while (readyCount < kThreadCount) {
}
// Constructor is called exactly `kThreadCount` times.
EXPECT_CALL(constructor(), Call(_)).Times(kThreadCount).WillRepeatedly([]() { throw kException; });
canStart = true;
threads.clear();
testing::Mock::VerifyAndClearExpectations(&constructor());
EXPECT_THAT(location, nullptr);
EXPECT_THAT(stackLocations, testing::Each(nullptr));
}
@@ -11,7 +11,6 @@
#include "Freezing.hpp"
#include "GC.hpp"
#include "GlobalsRegistry.hpp"
#include "InitializationScheme.hpp"
#include "KAssert.h"
#include "Natives.h"
#include "ObjectOps.hpp"
@@ -146,18 +145,6 @@ extern "C" OBJ_GETTER(AllocArrayInstance, const TypeInfo* typeInfo, int32_t elem
RETURN_RESULT_OF(mm::AllocateArray, threadData, typeInfo, static_cast<uint32_t>(elements));
}
extern "C" ALWAYS_INLINE OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
RETURN_RESULT_OF(mm::InitThreadLocalSingleton, threadData, location, typeInfo, ctor);
}
extern "C" ALWAYS_INLINE OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
RETURN_RESULT_OF(mm::InitSingleton, threadData, location, typeInfo, ctor);
}
extern "C" RUNTIME_NOTHROW void InitAndRegisterGlobal(ObjHeader** location, const ObjHeader* initialValue) {
auto* threadData = mm::ThreadRegistry::Instance().CurrentThreadData();
AssertThreadState(threadData, ThreadState::kRunnable);
@@ -4,12 +4,14 @@
*/
#include "ThreadLocalStorage.hpp"
#include "Logging.hpp"
using namespace kotlin;
void mm::ThreadLocalStorage::AddRecord(Key key, int size) noexcept {
RuntimeAssert(state_ == State::kBuilding, "Storage must be in the building state");
RuntimeAssert(size >= 0, "Size cannot be negative");
RuntimeLogDebug({kTagTLS}, "Add record key = %p, size = %d\n", key, size);
auto it = map_.find(key);
if (it != map_.end()) {
RuntimeAssert(it->second.size == size, "Attempt to add TLS record with the same key, but different size");
@@ -20,12 +22,14 @@ void mm::ThreadLocalStorage::AddRecord(Key key, int size) noexcept {
}
void mm::ThreadLocalStorage::Commit() noexcept {
RuntimeLogDebug({kTagTLS}, "Committed");
RuntimeAssert(state_ == State::kBuilding, "Storage must be in the building state");
storage_.resize(size_);
state_ = State::kCommitted;
}
void mm::ThreadLocalStorage::Clear() noexcept {
RuntimeLogDebug({kTagTLS}, "Cleared");
RuntimeAssert(state_ == State::kCommitted, "Storage must be in the committed state");
// Just free the storage.
storage_.clear();
@@ -33,6 +37,7 @@ void mm::ThreadLocalStorage::Clear() noexcept {
}
ObjHeader** mm::ThreadLocalStorage::Lookup(Key key, int index) noexcept {
RuntimeLogDebug({kTagTLS}, "Lookup key = %p, index = %d", key, index);
RuntimeAssert(state_ == State::kCommitted, "Storage must be in the committed state");
if (lastKeyAndEntry_.first == key) {
return Lookup(lastKeyAndEntry_.second, index);
@@ -44,6 +49,7 @@ ObjHeader** mm::ThreadLocalStorage::Lookup(Key key, int index) noexcept {
}
ObjHeader** mm::ThreadLocalStorage::Lookup(Entry entry, int index) noexcept {
RuntimeLogDebug({kTagTLS}, "Lookup entry = {%d, %d}, index = %d", entry.offset, entry.size, index);
RuntimeAssert(index < entry.size, "Out of bounds TLS access");
return &storage_[entry.offset + index];
}
@@ -19,14 +19,6 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* typeInfo, int32_t elements) {
RETURN_RESULT_OF(AllocArrayInstanceRelaxed, typeInfo, elements);
}
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(InitThreadLocalSingletonRelaxed, location, typeInfo, ctor);
}
OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(InitSingletonRelaxed, location, typeInfo, ctor);
}
RUNTIME_NOTHROW void ReleaseHeapRef(const ObjHeader* object) {
ReleaseHeapRefRelaxed(object);
}
@@ -19,14 +19,6 @@ OBJ_GETTER(AllocArrayInstance, const TypeInfo* typeInfo, int32_t elements) {
RETURN_RESULT_OF(AllocArrayInstanceStrict, typeInfo, elements);
}
OBJ_GETTER(InitThreadLocalSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(InitThreadLocalSingletonStrict, location, typeInfo, ctor);
}
OBJ_GETTER(InitSingleton, ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*)) {
RETURN_RESULT_OF(InitSingletonStrict, location, typeInfo, ctor);
}
RUNTIME_NOTHROW void ReleaseHeapRef(const ObjHeader* object) {
ReleaseHeapRefStrict(object);
}