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");
|
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());
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user