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");
// 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"
+17 -9
View File
@@ -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);
}
+2 -2
View File
@@ -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();
+60 -62
View File
@@ -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
}
-1
View File
@@ -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
+3 -2
View File
@@ -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);
}
}
+23
View File
@@ -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
+10 -9
View File
@@ -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;
}
+26 -25
View File
@@ -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);
+2 -1
View File
@@ -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);