Centralized memory allocation (#736)

This commit is contained in:
Nikolay Igotti
2017-07-13 14:10:26 +03:00
committed by GitHub
parent e8c1fbe1ff
commit dae273099a
11 changed files with 256 additions and 113 deletions
+111
View File
@@ -0,0 +1,111 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RUNTIME_ALLOC_H
#define RUNTIME_ALLOC_H
#include <stddef.h>
#include <stdlib.h>
#include <new>
#include <utility>
inline void* konanAllocMemory(size_t size) {
return calloc(1, size);
}
inline void konanFreeMemory(void* memory) {
free(memory);
}
template <typename T, typename ...A>
inline T* konanConstructInstance(A&& ...args) {
return new (konanAllocMemory(sizeof(T))) T(::std::forward<A>(args)...);
}
template <typename T, typename ...A>
inline T* konanConstructSizedInstance(size_t size, A&& ...args) {
return new (konanAllocMemory(size)) T(::std::forward<A>(args)...);
}
template <typename T>
inline void konanDestructInstance(T* instance) {
instance->~T();
konanFreeMemory(instance);
}
template <class T> class KonanAllocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
KonanAllocator() {}
KonanAllocator(const KonanAllocator&) {}
pointer allocate(size_type n, const void * = 0) {
return reinterpret_cast<T*>(konanAllocMemory(n * sizeof(T)));
}
void deallocate(void* p, size_type) {
if (p != nullptr) konanFreeMemory(p);
}
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
KonanAllocator<T>& operator=(const KonanAllocator&) { return *this; }
void construct(pointer p, const T& val) { new ((T*) p) T(val); }
// C++-11 wants that.
template <class U, class ...A>
void construct(U* const p, A&& ...args) {
new (p) U(::std::forward<A>(args)...);
}
void destroy(pointer p) { p->~T(); }
size_type max_size() const { return size_t(-1); }
template <class U>
struct rebind { typedef KonanAllocator<U> other; };
template <class U>
KonanAllocator(const KonanAllocator<U>&) {}
template <class U>
KonanAllocator& operator=(const KonanAllocator<U>&) { return *this; }
};
template <class T, class U>
bool operator==(
KonanAllocator<T> const&, KonanAllocator<U> const&) noexcept {
return true;
}
template <class T, class U>
bool operator!=(
KonanAllocator<T> const& x, KonanAllocator<U> const& y) noexcept {
return !(x == y);
}
#endif // RUNTIME_ALLOC_H
+2 -2
View File
@@ -41,7 +41,7 @@ void Kotlin_io_Console_print(KString message) {
RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string"); RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string");
// TODO: system stdout must be aware about UTF-8. // TODO: system stdout must be aware about UTF-8.
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0); const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
std::string utf8; KStdString utf8;
utf8::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8)); utf8::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8));
#ifdef KONAN_ANDROID #ifdef KONAN_ANDROID
__android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8.c_str()); __android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8.c_str());
@@ -71,4 +71,4 @@ OBJ_GETTER0(Kotlin_io_Console_readLine) {
RETURN_RESULT_OF(CreateStringFromCString, data); RETURN_RESULT_OF(CreateStringFromCString, data);
} }
} // extern "C" } // extern "C"
+17 -9
View File
@@ -14,7 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
#include "ExecFormat.h" #include "ExecFormat.h"
#include "Types.h"
#if USE_ELF_SYMBOLS #if USE_ELF_SYMBOLS
@@ -55,7 +57,9 @@ struct SymRecord {
char* strtab; char* strtab;
}; };
std::vector<SymRecord>* symbols = nullptr; typedef KStdVector<SymRecord> SymRecordList;
SymRecordList* symbols = nullptr;
// Unfortunately, symbol tables are stored in ELF sections not mapped // Unfortunately, symbol tables are stored in ELF sections not mapped
// during regular execution, so we have to map binary ourselves. // during regular execution, so we have to map binary ourselves.
@@ -71,7 +75,7 @@ Elf_Ehdr* findElfHeader() {
void initSymbols() { void initSymbols() {
RuntimeAssert(symbols == nullptr, "Init twice"); RuntimeAssert(symbols == nullptr, "Init twice");
symbols = new std::vector<SymRecord>(); symbols = konanConstructInstance<SymRecordList>();
Elf_Ehdr* ehdr = findElfHeader(); Elf_Ehdr* ehdr = findElfHeader();
if (ehdr == nullptr) return; if (ehdr == nullptr) return;
RuntimeAssert(strncmp((const char*)ehdr->e_ident, ELFMAG, SELFMAG) == 0, "Must be an ELF"); RuntimeAssert(strncmp((const char*)ehdr->e_ident, ELFMAG, SELFMAG) == 0, "Must be an ELF");
@@ -117,7 +121,7 @@ const char* addressToSymbol(const void* address) {
while (begin < end) { while (begin < end) {
// st_value is load address adjusted. // st_value is load address adjusted.
if (addressValue >= begin->st_value && addressValue < begin->st_value + begin->st_size) { if (addressValue >= begin->st_value && addressValue < begin->st_value + begin->st_size) {
return &record.strtab[begin->st_name]; return &record.strtab[begin->st_name];
} }
begin++; begin++;
} }
@@ -152,8 +156,12 @@ static void* mapModuleFile(HMODULE hModule) {
int bufferLength = 64; int bufferLength = 64;
wchar_t* buffer = nullptr; wchar_t* buffer = nullptr;
for (;;) { for (;;) {
buffer = (wchar_t*)realloc(buffer, sizeof(wchar_t) * bufferLength); auto newBuffer = (wchar_t*)konanAllocMemory(sizeof(wchar_t) * bufferLength);
RuntimeAssert(buffer != nullptr, "Out of memory"); RuntimeAssert(newBuffer != nullptr, "Out of memory");
if (buffer != nullptr) {
konanFreeMemory(buffer);
}
buffer = newBuffer;
DWORD res = GetModuleFileNameW(hModule, buffer, bufferLength); DWORD res = GetModuleFileNameW(hModule, buffer, bufferLength);
if (res != 0 && res < bufferLength) { if (res != 0 && res < bufferLength) {
@@ -167,7 +175,7 @@ static void* mapModuleFile(HMODULE hModule) {
} }
// Invalid result. // Invalid result.
free(buffer); konanFreeMemory(buffer);
return nullptr; return nullptr;
} }
@@ -180,7 +188,7 @@ static void* mapModuleFile(HMODULE hModule) {
/* dwFlagsAndAttributes = */ FILE_ATTRIBUTE_NORMAL, /* dwFlagsAndAttributes = */ FILE_ATTRIBUTE_NORMAL,
/* hTemplateFile = */ nullptr /* hTemplateFile = */ nullptr
); );
free(buffer); konanFreeMemory(buffer);
if (hFile == INVALID_HANDLE_VALUE) { if (hFile == INVALID_HANDLE_VALUE) {
// Can't open module file. // Can't open module file.
return nullptr; return nullptr;
@@ -263,7 +271,6 @@ class SymbolTable {
} }
public: public:
explicit SymbolTable(HMODULE hModule) { explicit SymbolTable(HMODULE hModule) {
imageBase = (char*)hModule; imageBase = (char*)hModule;
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)imageBase; IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)imageBase;
@@ -308,7 +315,8 @@ extern "C" bool AddressToSymbol(const void* address, char* resultBuffer, size_t
if (theExeSymbolTable == nullptr) { if (theExeSymbolTable == nullptr) {
// Note: do not protecting the lazy initialization by critical sections for simplicity; // Note: do not protecting the lazy initialization by critical sections for simplicity;
// this doesn't have any serious consequences. // this doesn't have any serious consequences.
theExeSymbolTable = new SymbolTable(GetModuleHandle(nullptr)); theExeSymbolTable = konanConstructInstance<SymbolTable>(
GetModuleHandle(nullptr));
} }
return theExeSymbolTable->functionAddressToSymbol(address, resultBuffer, resultBufferSize); return theExeSymbolTable->functionAddressToSymbol(address, resultBuffer, resultBufferSize);
} }
+2 -2
View File
@@ -668,7 +668,7 @@ int iswlower_Konan(KChar ch) {
return getType(ch) == LOWERCASE_LETTER; return getType(ch) == LOWERCASE_LETTER;
} }
void checkParsingErrors(const char* c_str, const char* end, std::string::size_type c_str_size) { void checkParsingErrors(const char* c_str, const char* end, KStdString::size_type c_str_size) {
if (end == c_str) { if (end == c_str) {
ThrowNumberFormatException(); ThrowNumberFormatException();
} }
@@ -736,7 +736,7 @@ OBJ_GETTER(Kotlin_String_toUtf8Array, KString thiz, KInt start, KInt size) {
ThrowArrayIndexOutOfBoundsException(); ThrowArrayIndexOutOfBoundsException();
} }
const KChar* utf16 = CharArrayAddressOfElementAt(thiz, start); const KChar* utf16 = CharArrayAddressOfElementAt(thiz, start);
std::string utf8; KStdString utf8;
utf8::utf16to8(utf16, utf16 + size, back_inserter(utf8)); utf8::utf16to8(utf16, utf16 + size, back_inserter(utf8));
ArrayHeader* result = AllocArrayInstance( ArrayHeader* result = AllocArrayInstance(
theByteArrayTypeInfo, utf8.size() + 1, OBJ_RESULT)->array(); theByteArrayTypeInfo, utf8.size() + 1, OBJ_RESULT)->array();
+60 -62
View File
@@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@@ -22,6 +21,7 @@
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include "Alloc.h"
#include "Assert.h" #include "Assert.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "Memory.h" #include "Memory.h"
@@ -57,9 +57,9 @@ constexpr size_t kGcThreshold = 9341;
#endif #endif
#if TRACE_MEMORY || USE_GC #if TRACE_MEMORY || USE_GC
typedef std::unordered_set<ContainerHeader*> ContainerHeaderSet; typedef KStdUnorderedSet<ContainerHeader*> ContainerHeaderSet;
typedef std::vector<ContainerHeader*> ContainerHeaderList; typedef KStdVector<ContainerHeader*> ContainerHeaderList;
typedef std::vector<KRef*> KRefPtrList; typedef KStdVector<KRef*> KRefPtrList;
#endif #endif
struct MemoryState { struct MemoryState {
@@ -96,16 +96,6 @@ namespace {
// TODO: can we pass this variable as an explicit argument? // TODO: can we pass this variable as an explicit argument?
__thread MemoryState* memoryState = nullptr; __thread MemoryState* memoryState = nullptr;
// TODO: use those allocators for STL containers as well.
template <typename T>
inline T* allocMemory(container_size_t size) {
return reinterpret_cast<T*>(calloc(1, size));
}
inline void freeMemory(void* memory) {
free(memory);
}
inline bool isFreeable(const ContainerHeader* header) { inline bool isFreeable(const ContainerHeader* header) {
return (header->refCount_ & CONTAINER_TAG_MASK) < CONTAINER_TAG_PERMANENT; return (header->refCount_ & CONTAINER_TAG_MASK) < CONTAINER_TAG_PERMANENT;
} }
@@ -118,6 +108,17 @@ inline container_size_t alignUp(container_size_t size, int alignment) {
return (size + alignment - 1) & ~(alignment - 1); return (size + alignment - 1) & ~(alignment - 1);
} }
// TODO: shall we do padding for alignment?
inline container_size_t objectSize(const ObjHeader* obj) {
const TypeInfo* type_info = obj->type_info();
container_size_t size = type_info->instanceSize_ < 0 ?
// An array.
ArrayDataSizeBytes(obj->array()) + sizeof(ArrayHeader)
:
type_info->instanceSize_ + sizeof(ObjHeader);
return alignUp(size, kObjectAlignment);
}
inline bool isArenaSlot(ObjHeader** slot) { inline bool isArenaSlot(ObjHeader** slot) {
return (reinterpret_cast<uintptr_t>(slot) & ARENA_BIT) != 0; return (reinterpret_cast<uintptr_t>(slot) & ARENA_BIT) != 0;
} }
@@ -205,10 +206,10 @@ inline void initThreshold(MemoryState* state, uint32_t gcThreshold) {
#if OPTIMIZE_GC #if OPTIMIZE_GC
if (state->toFreeCache != nullptr) { if (state->toFreeCache != nullptr) {
GarbageCollect(); GarbageCollect();
freeMemory(state->toFreeCache); konanFreeMemory(state->toFreeCache);
} }
state->toFreeCache = allocMemory<ContainerHeader*>( state->toFreeCache = reinterpret_cast<ContainerHeader**>(
sizeof(ContainerHeader*) * gcThreshold); konanAllocMemory(sizeof(ContainerHeader*) * gcThreshold));
state->cacheSize = 0; state->cacheSize = 0;
#endif #endif
state->gcThreshold = gcThreshold; state->gcThreshold = gcThreshold;
@@ -218,25 +219,28 @@ inline void initThreshold(MemoryState* state, uint32_t gcThreshold) {
ContainerHeaderList collectMutableReferred(ContainerHeader* header) { ContainerHeaderList collectMutableReferred(ContainerHeader* header) {
ContainerHeaderList result; ContainerHeaderList result;
ObjHeader* obj = reinterpret_cast<ObjHeader*>(header + 1); ObjHeader* obj = reinterpret_cast<ObjHeader*>(header + 1);
const TypeInfo* typeInfo = obj->type_info(); for (int object = 0; object < header->objectCount_; object++) {
// TODO: generalize iteration over all references. const TypeInfo* typeInfo = obj->type_info();
// TODO: this code relies on single object per container assumption. // TODO: generalize iteration over all references.
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) { for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
ObjHeader** location = reinterpret_cast<ObjHeader**>( ObjHeader** location = reinterpret_cast<ObjHeader**>(
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]); reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]);
ObjHeader* ref = *location; ObjHeader* ref = *location;
if (ref != nullptr && !isPermanent(ref->container())) {
result.push_back(ref->container());
}
}
if (typeInfo == theArrayTypeInfo) {
ArrayHeader* array = obj->array();
for (int index = 0; index < array->count_; index++) {
ObjHeader* ref = *ArrayAddressOfElementAt(array, index);
if (ref != nullptr && !isPermanent(ref->container())) { if (ref != nullptr && !isPermanent(ref->container())) {
result.push_back(ref->container()); result.push_back(ref->container());
} }
} }
if (typeInfo == theArrayTypeInfo) {
ArrayHeader* array = obj->array();
for (int index = 0; index < array->count_; index++) {
ObjHeader* ref = *ArrayAddressOfElementAt(array, index);
if (ref != nullptr && !isPermanent(ref->container())) {
result.push_back(ref->container());
}
}
}
obj = reinterpret_cast<ObjHeader*>(
reinterpret_cast<uintptr_t>(obj) + objectSize(obj));
} }
return result; return result;
} }
@@ -327,27 +331,16 @@ void phase4(ContainerHeader* header, ContainerHeaderSet* toRemove) {
inline ArenaContainer* initedArena(ObjHeader** auxSlot) { inline ArenaContainer* initedArena(ObjHeader** auxSlot) {
ObjHeader* slotValue = *auxSlot; ObjHeader* slotValue = *auxSlot;
if (slotValue) return reinterpret_cast<ArenaContainer*>(slotValue); if (slotValue) return reinterpret_cast<ArenaContainer*>(slotValue);
ArenaContainer* arena = allocMemory<ArenaContainer>(sizeof(ArenaContainer)); ArenaContainer* arena = konanConstructInstance<ArenaContainer>();
arena->Init(); arena->Init();
*auxSlot = reinterpret_cast<ObjHeader*>(arena); *auxSlot = reinterpret_cast<ObjHeader*>(arena);
return arena; return arena;
} }
// TODO: shall we do padding for alignment?
inline container_size_t objectSize(const ObjHeader* obj) {
const TypeInfo* type_info = obj->type_info();
container_size_t size = type_info->instanceSize_ < 0 ?
// An array.
ArrayDataSizeBytes(obj->array()) + sizeof(ArrayHeader)
:
type_info->instanceSize_ + sizeof(ObjHeader);
return alignUp(size, kObjectAlignment);
}
} // namespace } // namespace
ContainerHeader* AllocContainer(size_t size) { ContainerHeader* AllocContainer(size_t size) {
ContainerHeader* result = allocMemory<ContainerHeader>(size); ContainerHeader* result = konanConstructSizedInstance<ContainerHeader>(size);
#if TRACE_MEMORY #if TRACE_MEMORY
fprintf(stderr, ">>> alloc %d -> %p\n", static_cast<int>(size), result); fprintf(stderr, ">>> alloc %d -> %p\n", static_cast<int>(size), result);
memoryState->containers->insert(result); memoryState->containers->insert(result);
@@ -392,7 +385,7 @@ void FreeContainer(ContainerHeader* header) {
// And release underlying memory. // And release underlying memory.
if (isFreeable(header)) { if (isFreeable(header)) {
memoryState->allocCount--; memoryState->allocCount--;
freeMemory(header); konanFreeMemory(header);
} }
} }
@@ -407,7 +400,7 @@ void FreeContainerNoRef(ContainerHeader* header) {
removeFreeable(memoryState, header); removeFreeable(memoryState, header);
#endif #endif
memoryState->allocCount--; memoryState->allocCount--;
freeMemory(header); konanFreeMemory(header);
} }
#endif #endif
@@ -453,19 +446,24 @@ void ArenaContainer::Init() {
void ArenaContainer::Deinit() { void ArenaContainer::Deinit() {
auto chunk = currentChunk_; auto chunk = currentChunk_;
while (chunk != nullptr) { while (chunk != nullptr) {
auto toRemove = chunk;
// FreeContainer() doesn't release memory when CONTAINER_TAG_STACK is set. // FreeContainer() doesn't release memory when CONTAINER_TAG_STACK is set.
FreeContainer(chunk->asHeader()); FreeContainer(chunk->asHeader());
chunk = chunk->next; chunk = chunk->next;
freeMemory(toRemove);
} }
chunk = currentChunk_;
while (chunk != nullptr) {
auto toRemove = chunk;
chunk = chunk->next;
konanFreeMemory(toRemove);
}
} }
bool ArenaContainer::allocContainer(container_size_t minSize) { bool ArenaContainer::allocContainer(container_size_t minSize) {
auto size = minSize + sizeof(ContainerHeader) + sizeof(ContainerChunk); auto size = minSize + sizeof(ContainerHeader) + sizeof(ContainerChunk);
size = alignUp(size, kContainerAlignment); size = alignUp(size, kContainerAlignment);
// TODO: keep simple cache of container chunks. // TODO: keep simple cache of container chunks.
ContainerChunk* result = allocMemory<ContainerChunk>(size); ContainerChunk* result = konanConstructSizedInstance<ContainerChunk>(size);
RuntimeAssert(result != nullptr, "Cannot alloc memory"); RuntimeAssert(result != nullptr, "Cannot alloc memory");
if (result == nullptr) return false; if (result == nullptr) return false;
result->next = currentChunk_; result->next = currentChunk_;
@@ -560,15 +558,15 @@ MemoryState* InitMemory() {
offsetof(ObjHeader , container_offset_negative_), offsetof(ObjHeader , container_offset_negative_),
"Layout mismatch"); "Layout mismatch");
RuntimeAssert(memoryState == nullptr, "memory state must be clear"); RuntimeAssert(memoryState == nullptr, "memory state must be clear");
memoryState = allocMemory<MemoryState>(sizeof(MemoryState)); memoryState = konanConstructInstance<MemoryState>();
// TODO: initialize heap here. // TODO: initialize heap here.
memoryState->allocCount = 0; memoryState->allocCount = 0;
#if TRACE_MEMORY #if TRACE_MEMORY
memoryState->globalObjects = new KRefPtrList(); memoryState->globalObjects = konanConstructInstance<KRefPtrList>();
memoryState->containers = new ContainerHeaderSet(); memoryState->containers = konanConstructInstance<ContainerHeaderSet>();
#endif #endif
#if USE_GC #if USE_GC
memoryState->toFree = new ContainerHeaderSet(); memoryState->toFree = konanConstructInstance<ContainerHeaderSet>();
memoryState->gcInProgress = false; memoryState->gcInProgress = false;
initThreshold(memoryState, kGcThreshold); initThreshold(memoryState, kGcThreshold);
memoryState->gcSuspendCount = 0; memoryState->gcSuspendCount = 0;
@@ -583,18 +581,18 @@ void DeinitMemory(MemoryState* memoryState) {
fprintf(stderr, "Release global in *%p: %p\n", location, *location); fprintf(stderr, "Release global in *%p: %p\n", location, *location);
UpdateRef(location, nullptr); UpdateRef(location, nullptr);
} }
delete memoryState->globalObjects; konanDestructInstance(memoryState->globalObjects);
memoryState->globalObjects = nullptr; memoryState->globalObjects = nullptr;
#endif #endif
#if USE_GC #if USE_GC
GarbageCollect(); GarbageCollect();
delete memoryState->toFree; konanDestructInstance(memoryState->toFree);
memoryState->toFree = nullptr; memoryState->toFree = nullptr;
#if OPTIMIZE_GC #if OPTIMIZE_GC
if (memoryState->toFreeCache != nullptr) { if (memoryState->toFreeCache != nullptr) {
freeMemory(memoryState->toFreeCache); konanFreeMemory(memoryState->toFreeCache);
memoryState->toFreeCache = nullptr; memoryState->toFreeCache = nullptr;
} }
#endif #endif
@@ -605,12 +603,12 @@ void DeinitMemory(MemoryState* memoryState) {
#if TRACE_MEMORY #if TRACE_MEMORY
fprintf(stderr, "*** Memory leaks, leaked %d containers ***\n", memoryState->allocCount); fprintf(stderr, "*** Memory leaks, leaked %d containers ***\n", memoryState->allocCount);
dumpReachable("", memoryState->containers); dumpReachable("", memoryState->containers);
delete memoryState->containers; konanDestructInstance(memoryState->containers);
memoryState->containers = nullptr; memoryState->containers = nullptr;
#endif #endif
} }
freeMemory(memoryState); konanFreeMemory(memoryState);
::memoryState = nullptr; ::memoryState = nullptr;
} }
@@ -719,7 +717,7 @@ void LeaveFrame(ObjHeader** start, int count) {
fprintf(stderr, "LeaveFrame: free arena %p\n", arena); fprintf(stderr, "LeaveFrame: free arena %p\n", arena);
#endif #endif
arena->Deinit(); arena->Deinit();
freeMemory(arena); konanFreeMemory(arena);
} }
} }
@@ -836,7 +834,7 @@ void Kotlin_konan_internal_GC_stop(KRef) {
#if USE_GC #if USE_GC
if (memoryState->toFree != nullptr) { if (memoryState->toFree != nullptr) {
GarbageCollect(); GarbageCollect();
delete memoryState->toFree; konanDestructInstance(memoryState->toFree);
memoryState->toFree = nullptr; memoryState->toFree = nullptr;
} }
#endif #endif
@@ -845,7 +843,7 @@ void Kotlin_konan_internal_GC_stop(KRef) {
void Kotlin_konan_internal_GC_start(KRef) { void Kotlin_konan_internal_GC_start(KRef) {
#if USE_GC #if USE_GC
if (memoryState->toFree == nullptr) { if (memoryState->toFree == nullptr) {
memoryState->toFree = new ContainerHeaderSet(); memoryState->toFree = konanConstructInstance<ContainerHeaderSet>();
} }
#endif #endif
} }
-1
View File
@@ -45,7 +45,6 @@ typedef enum {
typedef uint32_t container_offset_t; typedef uint32_t container_offset_t;
typedef uint32_t container_size_t; typedef uint32_t container_size_t;
// Header of all container objects. Contains reference counter. // Header of all container objects. Contains reference counter.
struct ContainerHeader { struct ContainerHeader {
// Reference counter of container. Uses two lower bits of counter for // Reference counter of container. Uses two lower bits of counter for
+3 -2
View File
@@ -19,6 +19,7 @@
#include <windows.h> #include <windows.h>
#endif #endif
#include "Alloc.h"
#include "Memory.h" #include "Memory.h"
#include "Runtime.h" #include "Runtime.h"
@@ -63,7 +64,7 @@ void AppendToInitializersTail(InitNode *next) {
// TODO: properly use RuntimeState. // TODO: properly use RuntimeState.
RuntimeState* InitRuntime() { RuntimeState* InitRuntime() {
RuntimeState* result = new RuntimeState(); RuntimeState* result = konanConstructInstance<RuntimeState>();
result->memoryState = InitMemory(); result->memoryState = InitMemory();
// Keep global variables in state as well. // Keep global variables in state as well.
InitOrDeinitGlobalVariables(true); InitOrDeinitGlobalVariables(true);
@@ -80,7 +81,7 @@ void DeinitRuntime(RuntimeState* state) {
if (state != nullptr) { if (state != nullptr) {
InitOrDeinitGlobalVariables(false); InitOrDeinitGlobalVariables(false);
DeinitMemory(state->memoryState); DeinitMemory(state->memoryState);
delete state; konanDestructInstance(state);
} }
} }
+23
View File
@@ -17,6 +17,13 @@
#ifndef RUNTIME_TYPES_H #ifndef RUNTIME_TYPES_H
#define RUNTIME_TYPES_H #define RUNTIME_TYPES_H
#include <deque>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "Alloc.h"
#include "Common.h" #include "Common.h"
#include "Memory.h" #include "Memory.h"
#include "TypeInfo.h" #include "TypeInfo.h"
@@ -36,6 +43,22 @@ typedef ObjHeader* KRef;
typedef const ObjHeader* KConstRef; typedef const ObjHeader* KConstRef;
typedef const ArrayHeader* KString; typedef const ArrayHeader* KString;
// Definitions of STL classes used inside Konan runtime.
typedef std::basic_string<char, std::char_traits<char>,
KonanAllocator<char>> KStdString;
template<class Value>
using KStdDeque = std::deque<Value, KonanAllocator<Value>>;
template<class Key, class Value>
using KStdUnorderedMap = std::unordered_map<Key, Value,
std::hash<Key>, std::equal_to<Key>,
KonanAllocator<std::pair<const Key, Value>>>;
template<class Value>
using KStdUnorderedSet = std::unordered_set<Value,
std::hash<Value>, std::equal_to<Value>,
KonanAllocator<Value>>;
template<class Value>
using KStdVector = std::vector<Value, KonanAllocator<Value>>;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
+10 -9
View File
@@ -27,6 +27,7 @@
#include <unordered_map> #include <unordered_map>
#endif #endif
#include "Alloc.h"
#include "Assert.h" #include "Assert.h"
#include "Memory.h" #include "Memory.h"
#include "Runtime.h" #include "Runtime.h"
@@ -172,7 +173,7 @@ class Worker {
private: private:
KInt id_; KInt id_;
std::deque<Job> queue_; KStdDeque<Job> queue_;
// Lock and condition for waiting on the queue. // Lock and condition for waiting on the queue.
pthread_mutex_t lock_; pthread_mutex_t lock_;
pthread_cond_t cond_; pthread_cond_t cond_;
@@ -197,7 +198,7 @@ class State {
Worker* addWorkerUnlocked() { Worker* addWorkerUnlocked() {
Locker locker(&lock_); Locker locker(&lock_);
Worker* worker = new Worker(nextWorkerId()); Worker* worker = konanConstructInstance<Worker>(nextWorkerId());
if (worker == nullptr) return nullptr; if (worker == nullptr) return nullptr;
workers_[worker->id()] = worker; workers_[worker->id()] = worker;
return worker; return worker;
@@ -221,7 +222,7 @@ class State {
if (it == workers_.end()) return nullptr; if (it == workers_.end()) return nullptr;
worker = it->second; worker = it->second;
future = new Future(nextFutureId()); future = konanConstructInstance<Future>(nextFutureId());
futures_[future->id()] = future; futures_[future->id()] = future;
} }
@@ -259,7 +260,7 @@ class State {
auto it = futures_.find(id); auto it = futures_.find(id);
if (it != futures_.end()) { if (it != futures_.end()) {
futures_.erase(it); futures_.erase(it);
delete future; konanDestructInstance(future);
} }
} }
@@ -304,8 +305,8 @@ class State {
private: private:
pthread_mutex_t lock_; pthread_mutex_t lock_;
pthread_cond_t cond_; pthread_cond_t cond_;
std::unordered_map<KInt, Future*> futures_; KStdUnorderedMap<KInt, Future*> futures_;
std::unordered_map<KInt, Worker*> workers_; KStdUnorderedMap<KInt, Worker*> workers_;
KInt currentWorkerId_; KInt currentWorkerId_;
KInt currentFutureId_; KInt currentFutureId_;
KInt currentVersion_; KInt currentVersion_;
@@ -318,11 +319,11 @@ State* theState() {
return state; return state;
} }
State* result = new State(); State* result = konanConstructInstance<State>();
State* old = __sync_val_compare_and_swap(&state, nullptr, result); State* old = __sync_val_compare_and_swap(&state, nullptr, result);
if (old != nullptr) { if (old != nullptr) {
delete result; konanDestructInstance(result);
// Someone else inited this data. // Someone else inited this data.
return old; return old;
} }
@@ -377,7 +378,7 @@ void* workerRoutine(void* argument) {
DeinitRuntime(state); DeinitRuntime(state);
delete worker; konanDestructInstance(worker);
return nullptr; return nullptr;
} }
+26 -25
View File
@@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "cbigint.h" #include "cbigint.h"
#include "../KString.h"
#include "../Natives.h" #include "../Natives.h"
#include "../Exceptions.h" #include "../Exceptions.h"
#include "../utf8.h" #include "../utf8.h"
@@ -145,31 +146,31 @@ static const KDouble tens[] = {
* than twice. * than twice.
*/ */
#define INCREMENT_DOUBLE(_x, _decCount, _incCount) \ #define INCREMENT_DOUBLE(_x, _decCount, _incCount) \
{ \ { \
++DOUBLE_TO_LONGBITS(_x); \ ++DOUBLE_TO_LONGBITS(_x); \
_incCount++; \ _incCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \ if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \ if( _decCount > _incCount ) { \
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \ DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \ } else if( _incCount > _decCount ) { \
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \ DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
} \ } \
break; \ break; \
} \ } \
} }
#define DECREMENT_DOUBLE(_x, _decCount, _incCount) \ #define DECREMENT_DOUBLE(_x, _decCount, _incCount) \
{ \ { \
--DOUBLE_TO_LONGBITS(_x); \ --DOUBLE_TO_LONGBITS(_x); \
_decCount++; \ _decCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \ if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \ if( _decCount > _incCount ) { \
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \ DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \ } else if( _incCount > _decCount ) { \
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \ DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
} \ } \
break; \ break; \
} \ } \
} }
#define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0) #define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0)
#define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory; #define allocateU64(x, n) if (!((x) = (U_64*) malloc((n) * sizeof(U_64)))) goto OutOfMemory;
@@ -640,7 +641,7 @@ OutOfMemory:
KDouble Konan_FloatingPointParser_parseDoubleImpl (KString s, KInt e) KDouble Konan_FloatingPointParser_parseDoubleImpl (KString s, KInt e)
{ {
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0); const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
std::string utf8; KStdString utf8;
utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8));
const char *str = utf8.c_str(); const char *str = utf8.c_str();
auto dbl = createDouble (str, e); auto dbl = createDouble (str, e);
+2 -1
View File
@@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "cbigint.h" #include "cbigint.h"
#include "../KString.h"
#include "../Natives.h" #include "../Natives.h"
#include "../Exceptions.h" #include "../Exceptions.h"
#include "../utf8.h" #include "../utf8.h"
@@ -547,7 +548,7 @@ KFloat
Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e) Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e)
{ {
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0); const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
std::string utf8; KStdString utf8;
utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8));
const char *str = utf8.c_str(); const char *str = utf8.c_str();
auto flt = createFloat (str, e); auto flt = createFloat (str, e);