diff --git a/runtime/src/main/cpp/Alloc.h b/runtime/src/main/cpp/Alloc.h new file mode 100644 index 00000000000..5783e438148 --- /dev/null +++ b/runtime/src/main/cpp/Alloc.h @@ -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 +#include + +#include +#include + +inline void* konanAllocMemory(size_t size) { + return calloc(1, size); +} + +inline void konanFreeMemory(void* memory) { + free(memory); +} + +template +inline T* konanConstructInstance(A&& ...args) { + return new (konanAllocMemory(sizeof(T))) T(::std::forward(args)...); +} + +template +inline T* konanConstructSizedInstance(size_t size, A&& ...args) { + return new (konanAllocMemory(size)) T(::std::forward(args)...); +} + +template +inline void konanDestructInstance(T* instance) { + instance->~T(); + konanFreeMemory(instance); +} + +template 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(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& operator=(const KonanAllocator&) { return *this; } + + void construct(pointer p, const T& val) { new ((T*) p) T(val); } + + // C++-11 wants that. + template + void construct(U* const p, A&& ...args) { + new (p) U(::std::forward(args)...); + } + + void destroy(pointer p) { p->~T(); } + + size_type max_size() const { return size_t(-1); } + + template + struct rebind { typedef KonanAllocator other; }; + + template + KonanAllocator(const KonanAllocator&) {} + + template + KonanAllocator& operator=(const KonanAllocator&) { return *this; } +}; + +template +bool operator==( + KonanAllocator const&, KonanAllocator const&) noexcept { + return true; +} + +template +bool operator!=( + KonanAllocator const& x, KonanAllocator const& y) noexcept { + return !(x == y); +} + +#endif // RUNTIME_ALLOC_H diff --git a/runtime/src/main/cpp/Console.cpp b/runtime/src/main/cpp/Console.cpp index 62aa09810c0..b1e15716544 100644 --- a/runtime/src/main/cpp/Console.cpp +++ b/runtime/src/main/cpp/Console.cpp @@ -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" \ No newline at end of file +} // extern "C" diff --git a/runtime/src/main/cpp/ExecFormat.cpp b/runtime/src/main/cpp/ExecFormat.cpp index aaf083e1de5..ef8fbdacc48 100644 --- a/runtime/src/main/cpp/ExecFormat.cpp +++ b/runtime/src/main/cpp/ExecFormat.cpp @@ -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* symbols = nullptr; +typedef KStdVector 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(); + symbols = konanConstructInstance(); 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( + GetModuleHandle(nullptr)); } return theExeSymbolTable->functionAddressToSymbol(address, resultBuffer, resultBufferSize); } diff --git a/runtime/src/main/cpp/KString.cpp b/runtime/src/main/cpp/KString.cpp index 6fd64092258..6218a736c48 100644 --- a/runtime/src/main/cpp/KString.cpp +++ b/runtime/src/main/cpp/KString.cpp @@ -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(); diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 6cb9177a1c5..8ecf808b23f 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include @@ -22,6 +21,7 @@ #include #include +#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 ContainerHeaderSet; -typedef std::vector ContainerHeaderList; -typedef std::vector KRefPtrList; +typedef KStdUnorderedSet ContainerHeaderSet; +typedef KStdVector ContainerHeaderList; +typedef KStdVector 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 -inline T* allocMemory(container_size_t size) { - return reinterpret_cast(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(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( - sizeof(ContainerHeader*) * gcThreshold); + state->toFreeCache = reinterpret_cast( + 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(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( - reinterpret_cast(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( + reinterpret_cast(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( + reinterpret_cast(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(slotValue); - ArenaContainer* arena = allocMemory(sizeof(ArenaContainer)); + ArenaContainer* arena = konanConstructInstance(); arena->Init(); *auxSlot = reinterpret_cast(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(size); + ContainerHeader* result = konanConstructSizedInstance(size); #if TRACE_MEMORY fprintf(stderr, ">>> alloc %d -> %p\n", static_cast(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(size); + ContainerChunk* result = konanConstructSizedInstance(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(sizeof(MemoryState)); + memoryState = konanConstructInstance(); // TODO: initialize heap here. memoryState->allocCount = 0; #if TRACE_MEMORY - memoryState->globalObjects = new KRefPtrList(); - memoryState->containers = new ContainerHeaderSet(); + memoryState->globalObjects = konanConstructInstance(); + memoryState->containers = konanConstructInstance(); #endif #if USE_GC - memoryState->toFree = new ContainerHeaderSet(); + memoryState->toFree = konanConstructInstance(); 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(); } #endif } diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index 445c1112bf2..3bf141dd618 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -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 diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 20b977b64ce..ef3a99534ac 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -19,6 +19,7 @@ #include #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(); 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); } } diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index f945f6c27b3..4da60abb70c 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -17,6 +17,13 @@ #ifndef RUNTIME_TYPES_H #define RUNTIME_TYPES_H +#include +#include +#include +#include +#include + +#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, + KonanAllocator> KStdString; +template +using KStdDeque = std::deque>; +template +using KStdUnorderedMap = std::unordered_map, std::equal_to, + KonanAllocator>>; +template +using KStdUnorderedSet = std::unordered_set, std::equal_to, + KonanAllocator>; +template +using KStdVector = std::vector>; + #ifdef __cplusplus extern "C" { #endif diff --git a/runtime/src/main/cpp/Worker.cpp b/runtime/src/main/cpp/Worker.cpp index 406731c4166..96038aaaac1 100644 --- a/runtime/src/main/cpp/Worker.cpp +++ b/runtime/src/main/cpp/Worker.cpp @@ -27,6 +27,7 @@ #include #endif +#include "Alloc.h" #include "Assert.h" #include "Memory.h" #include "Runtime.h" @@ -172,7 +173,7 @@ class Worker { private: KInt id_; - std::deque queue_; + KStdDeque 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(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(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 futures_; - std::unordered_map workers_; + KStdUnorderedMap futures_; + KStdUnorderedMap workers_; KInt currentWorkerId_; KInt currentFutureId_; KInt currentVersion_; @@ -318,11 +319,11 @@ State* theState() { return state; } - State* result = new State(); + State* result = konanConstructInstance(); 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; } diff --git a/runtime/src/main/cpp/dtoa/dblparse.cpp b/runtime/src/main/cpp/dtoa/dblparse.cpp index 8bc8d4176f8..e124240d2bc 100644 --- a/runtime/src/main/cpp/dtoa/dblparse.cpp +++ b/runtime/src/main/cpp/dtoa/dblparse.cpp @@ -18,6 +18,7 @@ #include #include #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); diff --git a/runtime/src/main/cpp/dtoa/fltparse.cpp b/runtime/src/main/cpp/dtoa/fltparse.cpp index ce3da3d8ce7..f464d6a996b 100644 --- a/runtime/src/main/cpp/dtoa/fltparse.cpp +++ b/runtime/src/main/cpp/dtoa/fltparse.cpp @@ -18,6 +18,7 @@ #include #include #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);