Centralized memory allocation (#736)
This commit is contained in:
@@ -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
|
||||
@@ -41,7 +41,7 @@ void Kotlin_io_Console_print(KString message) {
|
||||
RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string");
|
||||
// TODO: system stdout must be aware about UTF-8.
|
||||
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
|
||||
std::string utf8;
|
||||
KStdString utf8;
|
||||
utf8::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8));
|
||||
#ifdef KONAN_ANDROID
|
||||
__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);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ExecFormat.h"
|
||||
#include "Types.h"
|
||||
|
||||
#if USE_ELF_SYMBOLS
|
||||
|
||||
@@ -55,7 +57,9 @@ struct SymRecord {
|
||||
char* strtab;
|
||||
};
|
||||
|
||||
std::vector<SymRecord>* symbols = nullptr;
|
||||
typedef KStdVector<SymRecord> SymRecordList;
|
||||
|
||||
SymRecordList* symbols = nullptr;
|
||||
|
||||
// Unfortunately, symbol tables are stored in ELF sections not mapped
|
||||
// during regular execution, so we have to map binary ourselves.
|
||||
@@ -71,7 +75,7 @@ Elf_Ehdr* findElfHeader() {
|
||||
|
||||
void initSymbols() {
|
||||
RuntimeAssert(symbols == nullptr, "Init twice");
|
||||
symbols = new std::vector<SymRecord>();
|
||||
symbols = konanConstructInstance<SymRecordList>();
|
||||
Elf_Ehdr* ehdr = findElfHeader();
|
||||
if (ehdr == nullptr) return;
|
||||
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) {
|
||||
// st_value is load address adjusted.
|
||||
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++;
|
||||
}
|
||||
@@ -152,8 +156,12 @@ static void* mapModuleFile(HMODULE hModule) {
|
||||
int bufferLength = 64;
|
||||
wchar_t* buffer = nullptr;
|
||||
for (;;) {
|
||||
buffer = (wchar_t*)realloc(buffer, sizeof(wchar_t) * bufferLength);
|
||||
RuntimeAssert(buffer != nullptr, "Out of memory");
|
||||
auto newBuffer = (wchar_t*)konanAllocMemory(sizeof(wchar_t) * bufferLength);
|
||||
RuntimeAssert(newBuffer != nullptr, "Out of memory");
|
||||
if (buffer != nullptr) {
|
||||
konanFreeMemory(buffer);
|
||||
}
|
||||
buffer = newBuffer;
|
||||
|
||||
DWORD res = GetModuleFileNameW(hModule, buffer, bufferLength);
|
||||
if (res != 0 && res < bufferLength) {
|
||||
@@ -167,7 +175,7 @@ static void* mapModuleFile(HMODULE hModule) {
|
||||
}
|
||||
|
||||
// Invalid result.
|
||||
free(buffer);
|
||||
konanFreeMemory(buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -180,7 +188,7 @@ static void* mapModuleFile(HMODULE hModule) {
|
||||
/* dwFlagsAndAttributes = */ FILE_ATTRIBUTE_NORMAL,
|
||||
/* hTemplateFile = */ nullptr
|
||||
);
|
||||
free(buffer);
|
||||
konanFreeMemory(buffer);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
// Can't open module file.
|
||||
return nullptr;
|
||||
@@ -263,7 +271,6 @@ class SymbolTable {
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit SymbolTable(HMODULE hModule) {
|
||||
imageBase = (char*)hModule;
|
||||
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) {
|
||||
// Note: do not protecting the lazy initialization by critical sections for simplicity;
|
||||
// this doesn't have any serious consequences.
|
||||
theExeSymbolTable = new SymbolTable(GetModuleHandle(nullptr));
|
||||
theExeSymbolTable = konanConstructInstance<SymbolTable>(
|
||||
GetModuleHandle(nullptr));
|
||||
}
|
||||
return theExeSymbolTable->functionAddressToSymbol(address, resultBuffer, resultBufferSize);
|
||||
}
|
||||
|
||||
@@ -668,7 +668,7 @@ int iswlower_Konan(KChar ch) {
|
||||
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) {
|
||||
ThrowNumberFormatException();
|
||||
}
|
||||
@@ -736,7 +736,7 @@ OBJ_GETTER(Kotlin_String_toUtf8Array, KString thiz, KInt start, KInt size) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
const KChar* utf16 = CharArrayAddressOfElementAt(thiz, start);
|
||||
std::string utf8;
|
||||
KStdString utf8;
|
||||
utf8::utf16to8(utf16, utf16 + size, back_inserter(utf8));
|
||||
ArrayHeader* result = AllocArrayInstance(
|
||||
theByteArrayTypeInfo, utf8.size() + 1, OBJ_RESULT)->array();
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -22,6 +21,7 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "Alloc.h"
|
||||
#include "Assert.h"
|
||||
#include "Exceptions.h"
|
||||
#include "Memory.h"
|
||||
@@ -57,9 +57,9 @@ constexpr size_t kGcThreshold = 9341;
|
||||
#endif
|
||||
|
||||
#if TRACE_MEMORY || USE_GC
|
||||
typedef std::unordered_set<ContainerHeader*> ContainerHeaderSet;
|
||||
typedef std::vector<ContainerHeader*> ContainerHeaderList;
|
||||
typedef std::vector<KRef*> KRefPtrList;
|
||||
typedef KStdUnorderedSet<ContainerHeader*> ContainerHeaderSet;
|
||||
typedef KStdVector<ContainerHeader*> ContainerHeaderList;
|
||||
typedef KStdVector<KRef*> KRefPtrList;
|
||||
#endif
|
||||
|
||||
struct MemoryState {
|
||||
@@ -96,16 +96,6 @@ namespace {
|
||||
// TODO: can we pass this variable as an explicit argument?
|
||||
__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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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 (state->toFreeCache != nullptr) {
|
||||
GarbageCollect();
|
||||
freeMemory(state->toFreeCache);
|
||||
konanFreeMemory(state->toFreeCache);
|
||||
}
|
||||
state->toFreeCache = allocMemory<ContainerHeader*>(
|
||||
sizeof(ContainerHeader*) * gcThreshold);
|
||||
state->toFreeCache = reinterpret_cast<ContainerHeader**>(
|
||||
konanAllocMemory(sizeof(ContainerHeader*) * gcThreshold));
|
||||
state->cacheSize = 0;
|
||||
#endif
|
||||
state->gcThreshold = gcThreshold;
|
||||
@@ -218,25 +219,28 @@ inline void initThreshold(MemoryState* state, uint32_t gcThreshold) {
|
||||
ContainerHeaderList collectMutableReferred(ContainerHeader* header) {
|
||||
ContainerHeaderList result;
|
||||
ObjHeader* obj = reinterpret_cast<ObjHeader*>(header + 1);
|
||||
const TypeInfo* typeInfo = obj->type_info();
|
||||
// TODO: generalize iteration over all references.
|
||||
// TODO: this code relies on single object per container assumption.
|
||||
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
||||
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
||||
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]);
|
||||
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);
|
||||
for (int object = 0; object < header->objectCount_; object++) {
|
||||
const TypeInfo* typeInfo = obj->type_info();
|
||||
// TODO: generalize iteration over all references.
|
||||
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
||||
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
||||
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]);
|
||||
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())) {
|
||||
result.push_back(ref->container());
|
||||
}
|
||||
}
|
||||
}
|
||||
obj = reinterpret_cast<ObjHeader*>(
|
||||
reinterpret_cast<uintptr_t>(obj) + objectSize(obj));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -327,27 +331,16 @@ void phase4(ContainerHeader* header, ContainerHeaderSet* toRemove) {
|
||||
inline ArenaContainer* initedArena(ObjHeader** auxSlot) {
|
||||
ObjHeader* slotValue = *auxSlot;
|
||||
if (slotValue) return reinterpret_cast<ArenaContainer*>(slotValue);
|
||||
ArenaContainer* arena = allocMemory<ArenaContainer>(sizeof(ArenaContainer));
|
||||
ArenaContainer* arena = konanConstructInstance<ArenaContainer>();
|
||||
arena->Init();
|
||||
*auxSlot = reinterpret_cast<ObjHeader*>(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
|
||||
|
||||
ContainerHeader* AllocContainer(size_t size) {
|
||||
ContainerHeader* result = allocMemory<ContainerHeader>(size);
|
||||
ContainerHeader* result = konanConstructSizedInstance<ContainerHeader>(size);
|
||||
#if TRACE_MEMORY
|
||||
fprintf(stderr, ">>> alloc %d -> %p\n", static_cast<int>(size), result);
|
||||
memoryState->containers->insert(result);
|
||||
@@ -392,7 +385,7 @@ void FreeContainer(ContainerHeader* header) {
|
||||
// And release underlying memory.
|
||||
if (isFreeable(header)) {
|
||||
memoryState->allocCount--;
|
||||
freeMemory(header);
|
||||
konanFreeMemory(header);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +400,7 @@ void FreeContainerNoRef(ContainerHeader* header) {
|
||||
removeFreeable(memoryState, header);
|
||||
#endif
|
||||
memoryState->allocCount--;
|
||||
freeMemory(header);
|
||||
konanFreeMemory(header);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -453,19 +446,24 @@ void ArenaContainer::Init() {
|
||||
void ArenaContainer::Deinit() {
|
||||
auto chunk = currentChunk_;
|
||||
while (chunk != nullptr) {
|
||||
auto toRemove = chunk;
|
||||
// FreeContainer() doesn't release memory when CONTAINER_TAG_STACK is set.
|
||||
FreeContainer(chunk->asHeader());
|
||||
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) {
|
||||
auto size = minSize + sizeof(ContainerHeader) + sizeof(ContainerChunk);
|
||||
size = alignUp(size, kContainerAlignment);
|
||||
// TODO: keep simple cache of container chunks.
|
||||
ContainerChunk* result = allocMemory<ContainerChunk>(size);
|
||||
ContainerChunk* result = konanConstructSizedInstance<ContainerChunk>(size);
|
||||
RuntimeAssert(result != nullptr, "Cannot alloc memory");
|
||||
if (result == nullptr) return false;
|
||||
result->next = currentChunk_;
|
||||
@@ -560,15 +558,15 @@ MemoryState* InitMemory() {
|
||||
offsetof(ObjHeader , container_offset_negative_),
|
||||
"Layout mismatch");
|
||||
RuntimeAssert(memoryState == nullptr, "memory state must be clear");
|
||||
memoryState = allocMemory<MemoryState>(sizeof(MemoryState));
|
||||
memoryState = konanConstructInstance<MemoryState>();
|
||||
// TODO: initialize heap here.
|
||||
memoryState->allocCount = 0;
|
||||
#if TRACE_MEMORY
|
||||
memoryState->globalObjects = new KRefPtrList();
|
||||
memoryState->containers = new ContainerHeaderSet();
|
||||
memoryState->globalObjects = konanConstructInstance<KRefPtrList>();
|
||||
memoryState->containers = konanConstructInstance<ContainerHeaderSet>();
|
||||
#endif
|
||||
#if USE_GC
|
||||
memoryState->toFree = new ContainerHeaderSet();
|
||||
memoryState->toFree = konanConstructInstance<ContainerHeaderSet>();
|
||||
memoryState->gcInProgress = false;
|
||||
initThreshold(memoryState, kGcThreshold);
|
||||
memoryState->gcSuspendCount = 0;
|
||||
@@ -583,18 +581,18 @@ void DeinitMemory(MemoryState* memoryState) {
|
||||
fprintf(stderr, "Release global in *%p: %p\n", location, *location);
|
||||
UpdateRef(location, nullptr);
|
||||
}
|
||||
delete memoryState->globalObjects;
|
||||
konanDestructInstance(memoryState->globalObjects);
|
||||
memoryState->globalObjects = nullptr;
|
||||
#endif
|
||||
|
||||
#if USE_GC
|
||||
GarbageCollect();
|
||||
delete memoryState->toFree;
|
||||
konanDestructInstance(memoryState->toFree);
|
||||
memoryState->toFree = nullptr;
|
||||
|
||||
#if OPTIMIZE_GC
|
||||
if (memoryState->toFreeCache != nullptr) {
|
||||
freeMemory(memoryState->toFreeCache);
|
||||
konanFreeMemory(memoryState->toFreeCache);
|
||||
memoryState->toFreeCache = nullptr;
|
||||
}
|
||||
#endif
|
||||
@@ -605,12 +603,12 @@ void DeinitMemory(MemoryState* memoryState) {
|
||||
#if TRACE_MEMORY
|
||||
fprintf(stderr, "*** Memory leaks, leaked %d containers ***\n", memoryState->allocCount);
|
||||
dumpReachable("", memoryState->containers);
|
||||
delete memoryState->containers;
|
||||
konanDestructInstance(memoryState->containers);
|
||||
memoryState->containers = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
freeMemory(memoryState);
|
||||
konanFreeMemory(memoryState);
|
||||
::memoryState = nullptr;
|
||||
}
|
||||
|
||||
@@ -719,7 +717,7 @@ void LeaveFrame(ObjHeader** start, int count) {
|
||||
fprintf(stderr, "LeaveFrame: free arena %p\n", arena);
|
||||
#endif
|
||||
arena->Deinit();
|
||||
freeMemory(arena);
|
||||
konanFreeMemory(arena);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,7 +834,7 @@ void Kotlin_konan_internal_GC_stop(KRef) {
|
||||
#if USE_GC
|
||||
if (memoryState->toFree != nullptr) {
|
||||
GarbageCollect();
|
||||
delete memoryState->toFree;
|
||||
konanDestructInstance(memoryState->toFree);
|
||||
memoryState->toFree = nullptr;
|
||||
}
|
||||
#endif
|
||||
@@ -845,7 +843,7 @@ void Kotlin_konan_internal_GC_stop(KRef) {
|
||||
void Kotlin_konan_internal_GC_start(KRef) {
|
||||
#if USE_GC
|
||||
if (memoryState->toFree == nullptr) {
|
||||
memoryState->toFree = new ContainerHeaderSet();
|
||||
memoryState->toFree = konanConstructInstance<ContainerHeaderSet>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ typedef enum {
|
||||
typedef uint32_t container_offset_t;
|
||||
typedef uint32_t container_size_t;
|
||||
|
||||
|
||||
// Header of all container objects. Contains reference counter.
|
||||
struct ContainerHeader {
|
||||
// Reference counter of container. Uses two lower bits of counter for
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "Alloc.h"
|
||||
#include "Memory.h"
|
||||
#include "Runtime.h"
|
||||
|
||||
@@ -63,7 +64,7 @@ void AppendToInitializersTail(InitNode *next) {
|
||||
|
||||
// TODO: properly use RuntimeState.
|
||||
RuntimeState* InitRuntime() {
|
||||
RuntimeState* result = new RuntimeState();
|
||||
RuntimeState* result = konanConstructInstance<RuntimeState>();
|
||||
result->memoryState = InitMemory();
|
||||
// Keep global variables in state as well.
|
||||
InitOrDeinitGlobalVariables(true);
|
||||
@@ -80,7 +81,7 @@ void DeinitRuntime(RuntimeState* state) {
|
||||
if (state != nullptr) {
|
||||
InitOrDeinitGlobalVariables(false);
|
||||
DeinitMemory(state->memoryState);
|
||||
delete state;
|
||||
konanDestructInstance(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
#ifndef 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 "Memory.h"
|
||||
#include "TypeInfo.h"
|
||||
@@ -36,6 +43,22 @@ typedef ObjHeader* KRef;
|
||||
typedef const ObjHeader* KConstRef;
|
||||
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
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <unordered_map>
|
||||
#endif
|
||||
|
||||
#include "Alloc.h"
|
||||
#include "Assert.h"
|
||||
#include "Memory.h"
|
||||
#include "Runtime.h"
|
||||
@@ -172,7 +173,7 @@ class Worker {
|
||||
|
||||
private:
|
||||
KInt id_;
|
||||
std::deque<Job> queue_;
|
||||
KStdDeque<Job> queue_;
|
||||
// Lock and condition for waiting on the queue.
|
||||
pthread_mutex_t lock_;
|
||||
pthread_cond_t cond_;
|
||||
@@ -197,7 +198,7 @@ class State {
|
||||
|
||||
Worker* addWorkerUnlocked() {
|
||||
Locker locker(&lock_);
|
||||
Worker* worker = new Worker(nextWorkerId());
|
||||
Worker* worker = konanConstructInstance<Worker>(nextWorkerId());
|
||||
if (worker == nullptr) return nullptr;
|
||||
workers_[worker->id()] = worker;
|
||||
return worker;
|
||||
@@ -221,7 +222,7 @@ class State {
|
||||
if (it == workers_.end()) return nullptr;
|
||||
worker = it->second;
|
||||
|
||||
future = new Future(nextFutureId());
|
||||
future = konanConstructInstance<Future>(nextFutureId());
|
||||
futures_[future->id()] = future;
|
||||
}
|
||||
|
||||
@@ -259,7 +260,7 @@ class State {
|
||||
auto it = futures_.find(id);
|
||||
if (it != futures_.end()) {
|
||||
futures_.erase(it);
|
||||
delete future;
|
||||
konanDestructInstance(future);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,8 +305,8 @@ class State {
|
||||
private:
|
||||
pthread_mutex_t lock_;
|
||||
pthread_cond_t cond_;
|
||||
std::unordered_map<KInt, Future*> futures_;
|
||||
std::unordered_map<KInt, Worker*> workers_;
|
||||
KStdUnorderedMap<KInt, Future*> futures_;
|
||||
KStdUnorderedMap<KInt, Worker*> workers_;
|
||||
KInt currentWorkerId_;
|
||||
KInt currentFutureId_;
|
||||
KInt currentVersion_;
|
||||
@@ -318,11 +319,11 @@ State* theState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
State* result = new State();
|
||||
State* result = konanConstructInstance<State>();
|
||||
|
||||
State* old = __sync_val_compare_and_swap(&state, nullptr, result);
|
||||
if (old != nullptr) {
|
||||
delete result;
|
||||
konanDestructInstance(result);
|
||||
// Someone else inited this data.
|
||||
return old;
|
||||
}
|
||||
@@ -377,7 +378,7 @@ void* workerRoutine(void* argument) {
|
||||
|
||||
DeinitRuntime(state);
|
||||
|
||||
delete worker;
|
||||
konanDestructInstance(worker);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "cbigint.h"
|
||||
#include "../KString.h"
|
||||
#include "../Natives.h"
|
||||
#include "../Exceptions.h"
|
||||
#include "../utf8.h"
|
||||
@@ -145,31 +146,31 @@ static const KDouble tens[] = {
|
||||
* than twice.
|
||||
*/
|
||||
#define INCREMENT_DOUBLE(_x, _decCount, _incCount) \
|
||||
{ \
|
||||
++DOUBLE_TO_LONGBITS(_x); \
|
||||
_incCount++; \
|
||||
if( (_incCount > 2) && (_decCount > 2) ) { \
|
||||
if( _decCount > _incCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
|
||||
} else if( _incCount > _decCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
{ \
|
||||
++DOUBLE_TO_LONGBITS(_x); \
|
||||
_incCount++; \
|
||||
if( (_incCount > 2) && (_decCount > 2) ) { \
|
||||
if( _decCount > _incCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
|
||||
} else if( _incCount > _decCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#define DECREMENT_DOUBLE(_x, _decCount, _incCount) \
|
||||
{ \
|
||||
--DOUBLE_TO_LONGBITS(_x); \
|
||||
_decCount++; \
|
||||
if( (_incCount > 2) && (_decCount > 2) ) { \
|
||||
if( _decCount > _incCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
|
||||
} else if( _incCount > _decCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
{ \
|
||||
--DOUBLE_TO_LONGBITS(_x); \
|
||||
_decCount++; \
|
||||
if( (_incCount > 2) && (_decCount > 2) ) { \
|
||||
if( _decCount > _incCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) += _decCount - _incCount; \
|
||||
} else if( _incCount > _decCount ) { \
|
||||
DOUBLE_TO_LONGBITS(_x) -= _incCount - _decCount; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#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;
|
||||
@@ -640,7 +641,7 @@ OutOfMemory:
|
||||
KDouble Konan_FloatingPointParser_parseDoubleImpl (KString s, KInt e)
|
||||
{
|
||||
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
|
||||
std::string utf8;
|
||||
KStdString utf8;
|
||||
utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8));
|
||||
const char *str = utf8.c_str();
|
||||
auto dbl = createDouble (str, e);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "cbigint.h"
|
||||
#include "../KString.h"
|
||||
#include "../Natives.h"
|
||||
#include "../Exceptions.h"
|
||||
#include "../utf8.h"
|
||||
@@ -547,7 +548,7 @@ KFloat
|
||||
Konan_FloatingPointParser_parseFloatImpl (KString s, KInt e)
|
||||
{
|
||||
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
|
||||
std::string utf8;
|
||||
KStdString utf8;
|
||||
utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8));
|
||||
const char *str = utf8.c_str();
|
||||
auto flt = createFloat (str, e);
|
||||
|
||||
Reference in New Issue
Block a user