Move everything under kotlin-native folder

I was forced to manually do update the following files, because otherwise
they would be ignored according .gitignore settings. Probably they
should be deleted from repo.

Interop/.idea/compiler.xml
Interop/.idea/gradle.xml
Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_3.xml
Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_3.xml
Interop/.idea/modules.xml
Interop/.idea/modules/Indexer/Indexer.iml
Interop/.idea/modules/Runtime/Runtime.iml
Interop/.idea/modules/StubGenerator/StubGenerator.iml
backend.native/backend.native.iml
backend.native/bc.frontend/bc.frontend.iml
backend.native/cli.bc/cli.bc.iml
backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt
backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt
backend.native/tests/link/lib/foo.kt
backend.native/tests/link/lib/foo2.kt
backend.native/tests/teamcity-test.property
This commit is contained in:
Stanislav Erokhin
2020-10-27 21:00:28 +03:00
parent 91e4162dad
commit f624800b84
2830 changed files with 0 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
/*
* 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>
#include "Porting.h"
inline void* konanAllocMemory(size_t size) {
return konan::calloc(1, size);
}
inline void konanFreeMemory(void* memory) {
konan::free(memory);
}
template<typename T>
inline T* konanAllocArray(size_t length) {
return reinterpret_cast<T*>(konanAllocMemory(length * sizeof(T)));
}
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
@@ -0,0 +1,708 @@
/*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include "KAssert.h"
#include "Exceptions.h"
#include "Memory.h"
#include "Natives.h"
#include "Types.h"
extern "C" void checkRangeIndexes(KInt from, KInt to, KInt size);
namespace {
ALWAYS_INLINE inline void mutabilityCheck(KConstRef thiz) {
// TODO: optimize it!
if (!thiz->local() && isFrozen(thiz)) {
ThrowInvalidMutabilityException(thiz);
}
}
ALWAYS_INLINE inline void boundsCheck(const ArrayHeader* array, KInt index) {
// We couldn't have created an array bigger than max KInt value.
// So if index is < 0, conversion to an unsigned value would make it bigger
// than the array size.
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
}
template<typename T>
inline void fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, T value) {
ArrayHeader* array = thiz->array();
checkRangeIndexes(fromIndex, toIndex, array->count_);
mutabilityCheck(thiz);
T* address = PrimitiveArrayAddressOfElementAt<T>(array, fromIndex);
for (KInt index = fromIndex; index < toIndex; ++index) {
*address++ = value;
}
}
template<typename T>
inline void copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
const ArrayHeader* array = thiz->array();
ArrayHeader* destinationArray = destination->array();
if (count < 0 ||
fromIndex < 0 || static_cast<uint32_t>(count) + fromIndex > array->count_ ||
toIndex < 0 || static_cast<uint32_t>(count) + toIndex > destinationArray->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(destination);
memmove(PrimitiveArrayAddressOfElementAt<T>(destinationArray, toIndex),
PrimitiveArrayAddressOfElementAt<T>(array, fromIndex),
count * sizeof(T));
}
template <class T>
inline void PrimitiveArraySet(KRef thiz, KInt index, T value) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<T>(array, index) = value;
}
template <class T>
inline T PrimitiveArrayGet(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return *PrimitiveArrayAddressOfElementAt<T>(array, index);
}
} // namespace
extern "C" {
// Generated as part of Kotlin standard library.
extern const ObjHeader theEmptyArray;
// TODO: those must be compiler intrinsics afterwards.
// Array.kt
OBJ_GETTER(Kotlin_Array_get, KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
boundsCheck(array, index);
RETURN_OBJ(*ArrayAddressOfElementAt(array, index));
}
void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
mutabilityCheck(thiz);
UpdateHeapRef(ArrayAddressOfElementAt(array, index), value);
}
KInt Kotlin_Array_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
void Kotlin_Array_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KRef value) {
ArrayHeader* array = thiz->array();
checkRangeIndexes(fromIndex, toIndex, array->count_);
mutabilityCheck(thiz);
for (KInt index = fromIndex; index < toIndex; ++index) {
UpdateHeapRef(ArrayAddressOfElementAt(array, index), value);
}
}
void Kotlin_Array_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
const ArrayHeader* array = thiz->array();
ArrayHeader* destinationArray = destination->array();
if (count < 0 ||
fromIndex < 0 || static_cast<uint32_t>(count) + fromIndex > array->count_ ||
toIndex < 0 || static_cast<uint32_t>(count) + toIndex > destinationArray->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(destination);
if (fromIndex >= toIndex) {
for (int index = 0; index < count; index++) {
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
*ArrayAddressOfElementAt(array, fromIndex + index));
}
} else {
for (int index = count - 1; index >= 0; index--) {
UpdateHeapRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
*ArrayAddressOfElementAt(array, fromIndex + index));
}
}
}
// Arrays.kt
OBJ_GETTER0(Kotlin_emptyArray) {
RETURN_OBJ(const_cast<ObjHeader*>(&theEmptyArray));
}
KByte Kotlin_ByteArray_get(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return *ByteArrayAddressOfElementAt(array, index);
}
void Kotlin_ByteArray_set(KRef thiz, KInt index, KByte value) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
mutabilityCheck(thiz);
*ByteArrayAddressOfElementAt(array, index) = value;
}
KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KChar Kotlin_ByteArray_getCharAt(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 1 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
#if KONAN_NO_UNALIGNED_ACCESS
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
return (static_cast<KChar>(address[0]) << 0) | (static_cast<KChar>(address[1]) << 8);
#else
auto result = *reinterpret_cast<const KChar*>(ByteArrayAddressOfElementAt(array, index));
#if __BIG_ENDIAN__
return __builtin_bswap16(result);
#else
return result;
#endif // __BIG_ENDIAN__
#endif // KONAN_NO_UNALIGNED_ACCESS
}
KShort Kotlin_ByteArray_getShortAt(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 1 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
#if KONAN_NO_UNALIGNED_ACCESS
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
return (static_cast<KShort>(address[0]) << 0) | (static_cast<KShort>(address[1]) << 8);
#else
auto result = *reinterpret_cast<const KShort*>(ByteArrayAddressOfElementAt(array, index));
#if __BIG_ENDIAN__
return __builtin_bswap16(result);
#else
return result;
#endif // __BIG_ENDIAN__
#endif // KONAN_NO_UNALIGNED_ACCESS
}
KInt Kotlin_ByteArray_getIntAt(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 3 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
#if KONAN_NO_UNALIGNED_ACCESS
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
return (static_cast<KInt>(address[0]) << 0) | (static_cast<KInt>(address[1]) << 8) |
(static_cast<KInt>(address[2]) << 16) | (static_cast<KInt>(address[3]) << 24);
#else
auto result = *reinterpret_cast<const KInt*>(ByteArrayAddressOfElementAt(array, index));
#if __BIG_ENDIAN__
return __builtin_bswap32(result);
#else
return result;
#endif // __BIG_ENDIAN__
#endif // KONAN_NO_UNALIGNED_ACCESS
}
KLong Kotlin_ByteArray_getLongAt(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 7 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
#if KONAN_NO_UNALIGNED_ACCESS
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
return (static_cast<KLong>(address[0]) << 0) | (static_cast<KLong>(address[1]) << 8) |
(static_cast<KLong>(address[2]) << 16) | (static_cast<KLong>(address[3]) << 24) |
(static_cast<KLong>(address[4]) << 32) | (static_cast<KLong>(address[5]) << 40) |
(static_cast<KLong>(address[6]) << 48) | (static_cast<KLong>(address[7]) << 56);
#else
auto result = *reinterpret_cast<const KLong*>(ByteArrayAddressOfElementAt(array, index));
#if __BIG_ENDIAN__
return __builtin_bswap64(result);
#else
return result;
#endif // __BIG_ENDIAN__
#endif // KONAN_NO_UNALIGNED_ACCESS
}
KFloat Kotlin_ByteArray_getFloatAt(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 3 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
#if KONAN_NO_UNALIGNED_ACCESS
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
union {
KFloat f;
uint8_t b[4];
} u;
#if __BIG_ENDIAN__
u.b[0] = address[3];
u.b[1] = address[2];
u.b[2] = address[1];
u.b[3] = address[0];
#else
u.b[0] = address[0];
u.b[1] = address[1];
u.b[2] = address[2];
u.b[3] = address[3];
#endif // __BIG_ENDIAN__
return u.f;
#else
auto result = *reinterpret_cast<const KFloat*>(ByteArrayAddressOfElementAt(array, index));
return result;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
KDouble Kotlin_ByteArray_getDoubleAt(KConstRef thiz, KInt index) {
const ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 7 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
#if KONAN_NO_UNALIGNED_ACCESS
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
union {
KDouble d;
uint8_t b[8];
} u;
#if __BIG_ENDIAN__
u.b[0] = address[7];
u.b[1] = address[6];
u.b[2] = address[5];
u.b[3] = address[4];
u.b[4] = address[3];
u.b[5] = address[2];
u.b[6] = address[1];
u.b[7] = address[0];
#else
u.b[0] = address[0];
u.b[1] = address[1];
u.b[2] = address[2];
u.b[3] = address[3];
u.b[4] = address[4];
u.b[5] = address[5];
u.b[6] = address[6];
u.b[7] = address[7];
#endif // __BIG_ENDIAN__
return u.d;
#else
return *reinterpret_cast<const KDouble*>(ByteArrayAddressOfElementAt(array, index));
#endif // KONAN_NO_UNALIGNED_ACCESS
}
void Kotlin_ByteArray_setCharAt(KRef thiz, KInt index, KChar value) {
ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 1 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
#if KONAN_NO_UNALIGNED_ACCESS
uint8_t* address = reinterpret_cast<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
address[0] = (value >> 0) & 0xff;
address[1] = (value >> 8) & 0xff;
#else
#if __BIG_ENDIAN__
value = __builtin_bswap16(value);
#endif // __BIG_ENDIAN__
*reinterpret_cast<KChar*>(ByteArrayAddressOfElementAt(array, index)) = value;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
void Kotlin_ByteArray_setShortAt(KRef thiz, KInt index, KShort value) {
ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 1 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
#if KONAN_NO_UNALIGNED_ACCESS
uint8_t* address = reinterpret_cast<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
address[0] = (value >> 0) & 0xff;
address[1] = (value >> 8) & 0xff;
#else
#if __BIG_ENDIAN__
value = __builtin_bswap16(value);
#endif
*reinterpret_cast<KShort*>(ByteArrayAddressOfElementAt(array, index)) = value;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
void Kotlin_ByteArray_setIntAt(KRef thiz, KInt index, KInt value) {
ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 3 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
#if KONAN_NO_UNALIGNED_ACCESS
uint8_t* address = reinterpret_cast<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
address[0] = (value >> 0) & 0xff;
address[1] = (value >> 8) & 0xff;
address[2] = (value >> 16) & 0xff;
address[3] = (value >> 24) & 0xff;
#else
#if __BIG_ENDIAN__
value = __builtin_bswap32(value);
#endif // __BIG_ENDIAN__
*reinterpret_cast<KInt*>(ByteArrayAddressOfElementAt(array, index)) = value;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
void Kotlin_ByteArray_setLongAt(KRef thiz, KInt index, KLong value) {
ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 7 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
#if KONAN_NO_UNALIGNED_ACCESS
uint8_t* address = reinterpret_cast<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
address[0] = (value >> 0) & 0xff;
address[1] = (value >> 8) & 0xff;
address[2] = (value >> 16) & 0xff;
address[3] = (value >> 24) & 0xff;
address[4] = (value >> 32) & 0xff;
address[5] = (value >> 40) & 0xff;
address[6] = (value >> 48) & 0xff;
address[7] = (value >> 56) & 0xff;
#else
#if __BIG_ENDIAN__
value = __builtin_bswap64(value);
#endif // __BIG_ENDIAN__
*reinterpret_cast<KLong*>(ByteArrayAddressOfElementAt(array, index)) = value;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
void Kotlin_ByteArray_setFloatAt(KRef thiz, KInt index, KFloat value) {
ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 3 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
#if KONAN_NO_UNALIGNED_ACCESS
uint8_t* address = reinterpret_cast<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
union {
KFloat f;
uint8_t b[4];
} u;
u.f = value;
address[0] = u.b[0];
address[1] = u.b[1];
address[2] = u.b[2];
address[3] = u.b[3];
#else
*reinterpret_cast<KFloat*>(ByteArrayAddressOfElementAt(array, index)) = value;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) {
ArrayHeader* array = thiz->array();
if (index < 0 || static_cast<uint32_t>(index) + 7 >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
#if KONAN_NO_UNALIGNED_ACCESS
uint8_t* address = reinterpret_cast<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
union {
KDouble d;
uint8_t b[8];
} u;
u.d = value;
address[0] = u.b[0];
address[1] = u.b[1];
address[2] = u.b[2];
address[3] = u.b[3];
address[4] = u.b[4];
address[5] = u.b[5];
address[6] = u.b[6];
address[7] = u.b[7];
#else
*reinterpret_cast<KDouble*>(ByteArrayAddressOfElementAt(array, index)) = value;
#endif // KONAN_NO_UNALIGNED_ACCESS
}
KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KChar>(thiz, index);
}
void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) {
PrimitiveArraySet(thiz, index, value);
}
OBJ_GETTER(Kotlin_CharArray_copyOf, KConstRef thiz, KInt newSize) {
const ArrayHeader* array = thiz->array();
if (newSize < 0) {
ThrowIllegalArgumentException();
}
ArrayHeader* result = AllocArrayInstance(array->type_info(), newSize, OBJ_RESULT)->array();
KInt toCopy = array->count_ < static_cast<uint32_t>(newSize) ? array->count_ : newSize;
memcpy(
PrimitiveArrayAddressOfElementAt<KChar>(result, 0),
PrimitiveArrayAddressOfElementAt<KChar>(array, 0),
toCopy * sizeof(KChar));
RETURN_OBJ(result->obj());
}
KInt Kotlin_CharArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KShort Kotlin_ShortArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KShort>(thiz, index);
}
void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KInt Kotlin_IntArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KInt>(thiz, index);
}
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_IntArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
void Kotlin_ByteArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KByte value) {
fillImpl<KByte>(thiz, fromIndex, toIndex, value);
}
void Kotlin_ShortArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KShort value) {
fillImpl<KShort>(thiz, fromIndex, toIndex, value);
}
void Kotlin_CharArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KChar value) {
fillImpl<KChar>(thiz, fromIndex, toIndex, value);
}
void Kotlin_IntArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KInt value) {
fillImpl<KInt>(thiz, fromIndex, toIndex, value);
}
void Kotlin_LongArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KLong value) {
fillImpl<KLong>(thiz, fromIndex, toIndex, value);
}
void Kotlin_FloatArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KFloat value) {
fillImpl<KFloat>(thiz, fromIndex, toIndex, value);
}
void Kotlin_DoubleArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KDouble value) {
fillImpl<KDouble>(thiz, fromIndex, toIndex, value);
}
void Kotlin_BooleanArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KBoolean value) {
fillImpl<KBoolean>(thiz, fromIndex, toIndex, value);
}
void Kotlin_ByteArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KByte>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_ShortArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KShort>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_CharArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KChar>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_IntArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KInt>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_LongArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KLong>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_FloatArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KFloat>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_DoubleArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KDouble>(thiz, fromIndex, destination, toIndex, count);
}
void Kotlin_BooleanArray_copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
copyImpl<KBoolean>(thiz, fromIndex, destination, toIndex, count);
}
KLong Kotlin_LongArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KLong>(thiz, index);
}
void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KFloat Kotlin_FloatArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KFloat>(thiz, index);
}
void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KDouble Kotlin_DoubleArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KDouble>(thiz, index);
}
void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KBoolean Kotlin_BooleanArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KBoolean>(thiz, index);
}
void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index) {
return PrimitiveArrayGet<KNativePtr>(thiz, index);
}
void Kotlin_NativePtrArray_set(KRef thiz, KInt index, KNativePtr value) {
PrimitiveArraySet(thiz, index, value);
}
KInt Kotlin_NativePtrArray_getArrayLength(KConstRef thiz) {
const ArrayHeader* array = thiz->array();
return array->count_;
}
OBJ_GETTER(Kotlin_ImmutableBlob_toByteArray, KConstRef thiz, KInt startIndex, KInt endIndex) {
const ArrayHeader* array = thiz->array();
if (startIndex < 0 || static_cast<uint32_t>(endIndex) > array->count_ || startIndex > endIndex) {
ThrowArrayIndexOutOfBoundsException();
}
KInt count = endIndex - startIndex;
ArrayHeader* result = AllocArrayInstance(theByteArrayTypeInfo, count, OBJ_RESULT)->array();
memcpy(PrimitiveArrayAddressOfElementAt<KByte>(result, 0),
PrimitiveArrayAddressOfElementAt<KByte>(array, startIndex),
count);
RETURN_OBJ(result->obj());
}
KNativePtr Kotlin_ImmutableBlob_asCPointerImpl(KRef thiz, KInt offset) {
ArrayHeader* array = thiz->array();
// We couldn't have created an array bigger than max KInt value.
// So if index is < 0, conversion to an unsigned value would make it bigger
// than the array size.
if (static_cast<uint32_t>(offset) > array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return PrimitiveArrayAddressOfElementAt<KByte>(array, offset);
}
KNativePtr Kotlin_Arrays_getByteArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return AddressOfElementAt<KByte>(array, index);
}
KNativePtr Kotlin_Arrays_getCharArrayAddressOfElement (KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return CharArrayAddressOfElementAt(array, index);
}
KNativePtr Kotlin_Arrays_getStringAddressOfElement (KRef thiz, KInt index) {
return Kotlin_Arrays_getCharArrayAddressOfElement(thiz, index);
}
KNativePtr Kotlin_Arrays_getShortArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return AddressOfElementAt<KShort>(array, index);
}
KNativePtr Kotlin_Arrays_getIntArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return AddressOfElementAt<KInt>(array, index);
}
KNativePtr Kotlin_Arrays_getLongArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return AddressOfElementAt<KLong>(array, index);
}
KNativePtr Kotlin_Arrays_getFloatArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return AddressOfElementAt<KFloat>(array, index);
}
KNativePtr Kotlin_Arrays_getDoubleArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
boundsCheck(array, index);
return AddressOfElementAt<KDouble>(array, index);
}
} // extern "C"
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "gtest/gtest.h"
#include "Porting.h"
// TODO: Replace these tests with real ones.
TEST(ArraysTest, GoodTest) {
konan::consolePrintf("I'm a good test\n");
EXPECT_EQ(true, true);
}
TEST(ArraysTest, BadTest) {
GTEST_SKIP();
konan::consolePrintf("I'm a bad test\n");
EXPECT_EQ(true, false);
}
@@ -0,0 +1,217 @@
/*
* Copyright 2010-2018 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.
*/
#include "Atomic.h"
#include "Common.h"
#include "Exceptions.h"
#include "Memory.h"
#include "Types.h"
namespace {
struct AtomicReferenceLayout {
ObjHeader header;
KRef value_;
KInt lock_;
KInt cookie_;
};
template<typename T> struct AtomicPrimitive {
ObjHeader header;
volatile T value_;
};
template <typename T> inline volatile T* getValueLocation(KRef thiz) {
AtomicPrimitive<T>* atomic = reinterpret_cast<AtomicPrimitive<T>*>(thiz);
return &atomic->value_;
}
template <typename T> void setImpl(KRef thiz, T value) {
volatile T* location = getValueLocation<T>(thiz);
atomicSet(location, value);
}
template <typename T> T getImpl(KRef thiz) {
volatile T* location = getValueLocation<T>(thiz);
return atomicGet(location);
}
template <typename T> T addAndGetImpl(KRef thiz, T delta) {
volatile T* location = getValueLocation<T>(thiz);
return atomicAdd(location, delta);
}
template <typename T> T compareAndSwapImpl(KRef thiz, T expectedValue, T newValue) {
volatile T* location = getValueLocation<T>(thiz);
return compareAndSwap(location, expectedValue, newValue);
}
template <typename T> KBoolean compareAndSetImpl(KRef thiz, T expectedValue, T newValue) {
volatile T* location = getValueLocation<T>(thiz);
return compareAndSet(location, expectedValue, newValue);
}
inline AtomicReferenceLayout* asAtomicReference(KRef thiz) {
return reinterpret_cast<AtomicReferenceLayout*>(thiz);
}
} // namespace
extern "C" {
KInt Kotlin_AtomicInt_addAndGet(KRef thiz, KInt delta) {
return addAndGetImpl(thiz, delta);
}
KInt Kotlin_AtomicInt_compareAndSwap(KRef thiz, KInt expectedValue, KInt newValue) {
return compareAndSwapImpl(thiz, expectedValue, newValue);
}
KBoolean Kotlin_AtomicInt_compareAndSet(KRef thiz, KInt expectedValue, KInt newValue) {
return compareAndSetImpl(thiz, expectedValue, newValue);
}
void Kotlin_AtomicInt_set(KRef thiz, KInt newValue) {
setImpl(thiz, newValue);
}
KInt Kotlin_AtomicInt_get(KRef thiz) {
return getImpl<KInt>(thiz);
}
KLong Kotlin_AtomicLong_addAndGet(KRef thiz, KLong delta) {
return addAndGetImpl(thiz, delta);
}
#if KONAN_NO_64BIT_ATOMIC
static int lock64 = 0;
#endif
KLong Kotlin_AtomicLong_compareAndSwap(KRef thiz, KLong expectedValue, KLong newValue) {
#if KONAN_NO_64BIT_ATOMIC
// Potentially huge performance penalty, but correct.
while (compareAndSwap(&lock64, 0, 1) != 0);
volatile KLong* address = getValueLocation<KLong>(thiz);
KLong old = *address;
if (old == expectedValue) {
*address = newValue;
}
compareAndSwap(&lock64, 1, 0);
return old;
#else
return compareAndSwapImpl(thiz, expectedValue, newValue);
#endif
}
KBoolean Kotlin_AtomicLong_compareAndSet(KRef thiz, KLong expectedValue, KLong newValue) {
#if KONAN_NO_64BIT_ATOMIC
// Potentially huge performance penalty, but correct.
KBoolean result = false;
while (compareAndSwap(&lock64, 0, 1) != 0);
volatile KLong* address = getValueLocation<KLong>(thiz);
KLong old = *address;
if (old == expectedValue) {
result = true;
*address = newValue;
}
compareAndSwap(&lock64, 1, 0);
return result;
#else
return compareAndSetImpl(thiz, expectedValue, newValue);
#endif
}
void Kotlin_AtomicLong_set(KRef thiz, KLong newValue) {
#if KONAN_NO_64BIT_ATOMIC
// Potentially huge performance penalty, but correct.
while (compareAndSwap(&lock64, 0, 1) != 0);
volatile KLong* address = getValueLocation<KLong>(thiz);
*address = newValue;
compareAndSwap(&lock64, 1, 0);
#else
setImpl(thiz, newValue);
#endif
}
KLong Kotlin_AtomicLong_get(KRef thiz) {
#if KONAN_NO_64BIT_ATOMIC
// Potentially huge performance penalty, but correct.
while (compareAndSwap(&lock64, 0, 1) != 0);
volatile KLong* address = getValueLocation<KLong>(thiz);
KLong value = *address;
compareAndSwap(&lock64, 1, 0);
return value;
#else
return getImpl<KLong>(thiz);
#endif
}
KNativePtr Kotlin_AtomicNativePtr_compareAndSwap(KRef thiz, KNativePtr expectedValue, KNativePtr newValue) {
return compareAndSwapImpl(thiz, expectedValue, newValue);
}
KBoolean Kotlin_AtomicNativePtr_compareAndSet(KRef thiz, KNativePtr expectedValue, KNativePtr newValue) {
return compareAndSetImpl(thiz, expectedValue, newValue);
}
void Kotlin_AtomicNativePtr_set(KRef thiz, KNativePtr newValue) {
setImpl(thiz, newValue);
}
KNativePtr Kotlin_AtomicNativePtr_get(KRef thiz) {
return getImpl<KNativePtr>(thiz);
}
void Kotlin_AtomicReference_checkIfFrozen(KRef value) {
if (value != nullptr && !isPermanentOrFrozen(value)) {
ThrowInvalidMutabilityException(value);
}
}
OBJ_GETTER(Kotlin_AtomicReference_compareAndSwap, KRef thiz, KRef expectedValue, KRef newValue) {
Kotlin_AtomicReference_checkIfFrozen(newValue);
// See Kotlin_AtomicReference_get() for explanations, why locking is needed.
AtomicReferenceLayout* ref = asAtomicReference(thiz);
RETURN_RESULT_OF(SwapHeapRefLocked, &ref->value_, expectedValue, newValue,
&ref->lock_, &ref->cookie_);
}
KBoolean Kotlin_AtomicReference_compareAndSet(KRef thiz, KRef expectedValue, KRef newValue) {
Kotlin_AtomicReference_checkIfFrozen(newValue);
// See Kotlin_AtomicReference_get() for explanations, why locking is needed.
AtomicReferenceLayout* ref = asAtomicReference(thiz);
ObjHolder holder;
auto old = SwapHeapRefLocked(&ref->value_, expectedValue, newValue,
&ref->lock_, &ref->cookie_, holder.slot());
return old == expectedValue;
}
void Kotlin_AtomicReference_set(KRef thiz, KRef newValue) {
Kotlin_AtomicReference_checkIfFrozen(newValue);
AtomicReferenceLayout* ref = asAtomicReference(thiz);
SetHeapRefLocked(&ref->value_, newValue, &ref->lock_, &ref->cookie_);
}
OBJ_GETTER(Kotlin_AtomicReference_get, KRef thiz) {
// Here we must take a lock to prevent race when value, while taken here, is CASed and immediately
// destroyed by an another thread. AtomicReference no longer holds such an object, so if we got
// rescheduled unluckily, between the moment value is read from the field and RC is incremented,
// object may go away.
AtomicReferenceLayout* ref = asAtomicReference(thiz);
RETURN_RESULT_OF(ReadHeapRefLocked, &ref->value_, &ref->lock_, &ref->cookie_);
}
} // extern "C"
@@ -0,0 +1,80 @@
#ifndef RUNTIME_ATOMIC_H
#define RUNTIME_ATOMIC_H
#include "Common.h"
template <typename T>
ALWAYS_INLINE inline T atomicAdd(volatile T* where, T what) {
#ifndef KONAN_NO_THREADS
return __sync_add_and_fetch(where, what);
#else
return *where += what;
#endif
}
template <typename T>
ALWAYS_INLINE inline T compareAndSwap(volatile T* where, T expectedValue, T newValue) {
#ifndef KONAN_NO_THREADS
return __sync_val_compare_and_swap(where, expectedValue, newValue);
#else
T oldValue = *where;
if (oldValue == expectedValue) {
*where = newValue;
}
return oldValue;
#endif
}
template <typename T>
ALWAYS_INLINE inline bool compareAndSet(volatile T* where, T expectedValue, T newValue) {
#ifndef KONAN_NO_THREADS
return __sync_bool_compare_and_swap(where, expectedValue, newValue);
#else
T oldValue = *where;
if (oldValue == expectedValue) {
*where = newValue;
return true;
}
return false;
#endif
}
#pragma clang diagnostic push
#if (KONAN_ANDROID || KONAN_IOS || KONAN_WATCHOS || KONAN_LINUX) && (KONAN_ARM32 || KONAN_X86 || KONAN_MIPS32 || KONAN_MIPSEL32)
// On 32-bit Android clang generates library calls for "large" atomic operations
// and warns about "significant performance penalty". See more details here:
// https://github.com/llvm/llvm-project/blob/ce56e1a1cc5714f4af5675dd963cfebed766d9e1/clang/lib/CodeGen/CGAtomic.cpp#L775
// Ignore these warnings:
#pragma clang diagnostic ignored "-Watomic-alignment"
#endif
template <typename T>
ALWAYS_INLINE inline void atomicSet(volatile T* where, T what) {
#ifndef KONAN_NO_THREADS
__atomic_store(where, &what, __ATOMIC_SEQ_CST);
#else
*where = what;
#endif
}
template <typename T>
ALWAYS_INLINE inline T atomicGet(volatile T* where) {
#ifndef KONAN_NO_THREADS
T what;
__atomic_load(where, &what, __ATOMIC_SEQ_CST);
return what;
#else
return *where;
#endif
}
#pragma clang diagnostic pop
static ALWAYS_INLINE inline void synchronize() {
#ifndef KONAN_NO_THREADS
__sync_synchronize();
#endif
}
#endif // RUNTIME_ATOMIC_H
@@ -0,0 +1,121 @@
/*
* Copyright 2010-2018 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.
*/
#include "Memory.h"
#include "Types.h"
// C++ part of box caching.
template<class T>
struct KBox {
ObjHeader header;
const T value;
};
// Keep naming of these in sync with codegen part.
extern const KBoolean BOOLEAN_RANGE_FROM;
extern const KBoolean BOOLEAN_RANGE_TO;
extern const KByte BYTE_RANGE_FROM;
extern const KByte BYTE_RANGE_TO;
extern const KChar CHAR_RANGE_FROM;
extern const KChar CHAR_RANGE_TO;
extern const KShort SHORT_RANGE_FROM;
extern const KShort SHORT_RANGE_TO;
extern const KInt INT_RANGE_FROM;
extern const KInt INT_RANGE_TO;
extern const KLong LONG_RANGE_FROM;
extern const KLong LONG_RANGE_TO;
extern KBox<KBoolean> BOOLEAN_CACHE[];
extern KBox<KByte> BYTE_CACHE[];
extern KBox<KChar> CHAR_CACHE[];
extern KBox<KShort> SHORT_CACHE[];
extern KBox<KInt> INT_CACHE[];
extern KBox<KLong> LONG_CACHE[];
namespace {
template<class T>
inline bool isInRange(T value, T from, T to) {
return value >= from && value <= to;
}
template<class T>
OBJ_GETTER(getCachedBox, T value, KBox<T> cache[], T from) {
uint64_t index = value - from;
RETURN_OBJ(&cache[index].header);
}
} // namespace
extern "C" {
bool inBooleanBoxCache(KBoolean value) {
return isInRange(value, BOOLEAN_RANGE_FROM, BOOLEAN_RANGE_TO);
}
bool inByteBoxCache(KByte value) {
return isInRange(value, BYTE_RANGE_FROM, BYTE_RANGE_TO);
}
bool inCharBoxCache(KChar value) {
return isInRange(value, CHAR_RANGE_FROM, CHAR_RANGE_TO);
}
bool inShortBoxCache(KShort value) {
return isInRange(value, SHORT_RANGE_FROM, SHORT_RANGE_TO);
}
bool inIntBoxCache(KInt value) {
return isInRange(value, INT_RANGE_FROM, INT_RANGE_TO);
}
bool inLongBoxCache(KLong value) {
return isInRange(value, LONG_RANGE_FROM, LONG_RANGE_TO);
}
OBJ_GETTER(getCachedBooleanBox, KBoolean value) {
RETURN_RESULT_OF(getCachedBox, value, BOOLEAN_CACHE, BOOLEAN_RANGE_FROM);
}
OBJ_GETTER(getCachedByteBox, KByte value) {
// Remember that KByte can't handle values >= 127
// so it can't be used as indexing type.
RETURN_RESULT_OF(getCachedBox, value, BYTE_CACHE, BYTE_RANGE_FROM);
}
OBJ_GETTER(getCachedCharBox, KChar value) {
RETURN_RESULT_OF(getCachedBox, value, CHAR_CACHE, CHAR_RANGE_FROM);
}
OBJ_GETTER(getCachedShortBox, KShort value) {
RETURN_RESULT_OF(getCachedBox, value, SHORT_CACHE, SHORT_RANGE_FROM);
}
OBJ_GETTER(getCachedIntBox, KInt value) {
RETURN_RESULT_OF(getCachedBox, value, INT_CACHE, INT_RANGE_FROM);
}
OBJ_GETTER(getCachedLongBox, KLong value) {
RETURN_RESULT_OF(getCachedBox, value, LONG_CACHE, LONG_RANGE_FROM);
}
}
@@ -0,0 +1,130 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Cleaner.h"
#include "Memory.h"
#include "Runtime.h"
#include "Worker.h"
// Defined in Cleaner.kt
extern "C" void Kotlin_CleanerImpl_shutdownCleanerWorker(KInt, bool);
extern "C" KInt Kotlin_CleanerImpl_createCleanerWorker();
namespace {
struct CleanerImpl {
ObjHeader header;
KNativePtr cleanerStablePtr;
};
constexpr KInt kCleanerWorkerUninitialized = 0;
constexpr KInt kCleanerWorkerInitializing = -1;
constexpr KInt kCleanerWorkerShutdown = -2;
KInt globalCleanerWorker = kCleanerWorkerUninitialized;
void disposeCleaner(CleanerImpl* thiz) {
auto worker = atomicGet(&globalCleanerWorker);
RuntimeAssert(
worker != kCleanerWorkerUninitialized && worker != kCleanerWorkerInitializing,
"Cleaner worker must've been initialized by now");
if (worker == kCleanerWorkerShutdown) {
if (Kotlin_cleanersLeakCheckerEnabled()) {
konan::consoleErrorf(
"Cleaner %p was disposed during program exit\n"
"Use `Platform.isCleanersLeakCheckerActive = false` to avoid this check.\n",
thiz);
RuntimeCheck(false, "Terminating now");
}
return;
}
RuntimeAssert(worker > 0, "Cleaner worker must be fully initialized here");
bool result = WorkerSchedule(worker, thiz->cleanerStablePtr);
RuntimeAssert(result, "Couldn't find Cleaner worker");
}
} // namespace
RUNTIME_NOTHROW void DisposeCleaner(KRef thiz) {
#if KONAN_NO_EXCEPTIONS
disposeCleaner(reinterpret_cast<CleanerImpl*>(thiz));
#else
try {
disposeCleaner(reinterpret_cast<CleanerImpl*>(thiz));
} catch (...) {
// A trick to terminate with unhandled exception. This will print a stack trace
// and write to iOS crash log.
std::terminate();
}
#endif
}
void ShutdownCleaners(bool executeScheduledCleaners) {
KInt worker = 0;
do {
worker = atomicGet(&globalCleanerWorker);
RuntimeAssert(worker != kCleanerWorkerShutdown, "Cleaner worker must not be shutdown twice");
if (worker == kCleanerWorkerUninitialized) {
if (!compareAndSet(&globalCleanerWorker, kCleanerWorkerUninitialized, kCleanerWorkerShutdown)) {
// Someone is trying to initialize the worker. Try again.
continue;
}
// worker was never initialized. Just return.
return;
}
if (worker == kCleanerWorkerInitializing) {
// Someone is trying to initialize the worker. Try again.
continue;
}
// Worker is in some proper state.
break;
} while (true);
RuntimeAssert(worker > 0, "Cleaner worker must be fully initialized here");
atomicSet(&globalCleanerWorker, kCleanerWorkerShutdown);
Kotlin_CleanerImpl_shutdownCleanerWorker(worker, executeScheduledCleaners);
WaitNativeWorkerTermination(worker);
}
extern "C" KInt Kotlin_CleanerImpl_getCleanerWorker() {
KInt worker = 0;
do {
worker = atomicGet(&globalCleanerWorker);
RuntimeAssert(worker != kCleanerWorkerShutdown, "Cleaner worker must not have been shutdown");
if (worker == kCleanerWorkerUninitialized) {
if (!compareAndSet(&globalCleanerWorker, kCleanerWorkerUninitialized, kCleanerWorkerInitializing)) {
// Someone else is trying to initialize the worker. Try again.
continue;
}
worker = Kotlin_CleanerImpl_createCleanerWorker();
if (!compareAndSet(&globalCleanerWorker, kCleanerWorkerInitializing, worker)) {
RuntimeCheck(false, "Someone interrupted worker initializing");
}
// Worker is initialized.
break;
}
if (worker == kCleanerWorkerInitializing) {
// Someone is trying to initialize the worker. Try again.
continue;
}
// Worker is in some proper state.
break;
} while (true);
RuntimeAssert(worker > 0, "Cleaner worker must be fully initialized here");
return worker;
}
void ResetCleanerWorkerForTests() {
atomicSet(&globalCleanerWorker, kCleanerWorkerUninitialized);
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_CLEANER_H
#define RUNTIME_CLEANER_H
#include "Common.h"
#include "Types.h"
RUNTIME_NOTHROW void DisposeCleaner(KRef thiz);
void ShutdownCleaners(bool executeScheduledCleaners);
extern "C" KInt Kotlin_CleanerImpl_getCleanerWorker();
void ResetCleanerWorkerForTests();
#endif // RUNTIME_CLEANER_H
@@ -0,0 +1,80 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Cleaner.h"
#include <future>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "Atomic.h"
#include "TestSupportCompilerGenerated.hpp"
using testing::_;
// TODO: Also test disposal. (This requires extracting Worker interface)
TEST(CleanerTest, ConcurrentCreation) {
ResetCleanerWorkerForTests();
constexpr int threadCount = 100;
constexpr KInt workerId = 42;
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
EXPECT_CALL(*createCleanerWorkerMock, Call()).Times(1).WillOnce(testing::Return(workerId));
int startedThreads = 0;
bool allowRunning = false;
std::vector<std::future<KInt>> futures;
for (int i = 0; i < threadCount; ++i) {
auto future = std::async(std::launch::async, [&startedThreads, &allowRunning]() {
atomicAdd(&startedThreads, 1);
while (!atomicGet(&allowRunning)) {
}
return Kotlin_CleanerImpl_getCleanerWorker();
});
futures.push_back(std::move(future));
}
while (atomicGet(&startedThreads) != threadCount) {
}
atomicSet(&allowRunning, true);
std::vector<KInt> values;
for (auto& future : futures) {
values.push_back(future.get());
}
ASSERT_THAT(values.size(), threadCount);
EXPECT_THAT(values, testing::Each(workerId));
}
TEST(CleanerTest, ShutdownWithoutCreation) {
ResetCleanerWorkerForTests();
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
auto shutdownCleanerWorkerMock = ScopedShutdownCleanerWorkerMock();
EXPECT_CALL(*createCleanerWorkerMock, Call()).Times(0);
EXPECT_CALL(*shutdownCleanerWorkerMock, Call(_, _)).Times(0);
ShutdownCleaners(true);
}
TEST(CleanerTest, ShutdownWithCreation) {
ResetCleanerWorkerForTests();
constexpr KInt workerId = 42;
constexpr bool executeScheduledCleaners = true;
auto createCleanerWorkerMock = ScopedCreateCleanerWorkerMock();
auto shutdownCleanerWorkerMock = ScopedShutdownCleanerWorkerMock();
EXPECT_CALL(*createCleanerWorkerMock, Call()).WillOnce(testing::Return(workerId));
Kotlin_CleanerImpl_getCleanerWorker();
EXPECT_CALL(*shutdownCleanerWorkerMock, Call(workerId, executeScheduledCleaners));
ShutdownCleaners(executeScheduledCleaners);
}
@@ -0,0 +1,42 @@
/*
* 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_COMMON_H
#define RUNTIME_COMMON_H
#define RUNTIME_NOTHROW __attribute__((nothrow))
#define RUNTIME_NORETURN __attribute__((noreturn))
#define RUNTIME_CONST __attribute__((const))
#define RUNTIME_PURE __attribute__((pure))
#define RUNTIME_USED __attribute__((used))
#define RUNTIME_WEAK __attribute__((weak))
#define ALWAYS_INLINE __attribute__((always_inline))
#define NO_INLINE __attribute__((noinline))
#if KONAN_NO_THREADS
#define THREAD_LOCAL_VARIABLE
#else
#define THREAD_LOCAL_VARIABLE __thread
#endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#if KONAN_OBJC_INTEROP
#define KONAN_TYPE_INFO_HAS_WRITABLE_PART 1
#endif
#endif // RUNTIME_COMMON_H
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Memory.h"
namespace {
template <typename T>
T defaultValue() {
return T();
}
template <typename Ret, typename... Args>
void ensureUsed(Ret (*f)(Args...)) {
f(defaultValue<Args>()...);
}
} // namespace
// This is a hack to force clang to emit possibly unused declarations.
// TODO: Make sure this function gets DCE'd in the final binary.
// TODO: Should be done with some sort of annotation on the declaration.
void EnsureDeclarationsEmitted() {
ensureUsed(AllocInstance);
ensureUsed(AllocArrayInstance);
ensureUsed(InitInstance);
ensureUsed(InitSharedInstance);
ensureUsed(UpdateHeapRef);
ensureUsed(UpdateStackRef);
ensureUsed(UpdateReturnRef);
ensureUsed(ZeroHeapRef);
ensureUsed(ZeroArrayRefs);
ensureUsed(EnterFrame);
ensureUsed(LeaveFrame);
ensureUsed(AddTLSRecord);
ensureUsed(ClearTLSRecord);
ensureUsed(LookupTLS);
ensureUsed(MutationCheck);
ensureUsed(CheckLifetimesConstraint);
ensureUsed(FreezeSubgraph);
ensureUsed(FreezeSubgraph);
}
@@ -0,0 +1,62 @@
/*
* 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.
*/
#include "KAssert.h"
#include "Memory.h"
#include "Natives.h"
#include "KString.h"
#include "Porting.h"
#include "Types.h"
#include "Exceptions.h"
#include "utf8.h"
extern "C" {
// io/Console.kt
void Kotlin_io_Console_print(KString message) {
if (message->type_info() != theStringTypeInfo) {
ThrowClassCastException(message->obj(), theStringTypeInfo);
}
// TODO: system stdout must be aware about UTF-8.
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
KStdString utf8;
utf8.reserve(message->count_);
// Replace incorrect sequences with a default codepoint (see utf8::with_replacement::default_replacement)
utf8::with_replacement::utf16to8(utf16, utf16 + message->count_, back_inserter(utf8));
konan::consoleWriteUtf8(utf8.c_str(), utf8.size());
}
void Kotlin_io_Console_println(KString message) {
Kotlin_io_Console_print(message);
#ifndef KONAN_ANDROID
// On Android single print produces logcat entry, so no need in linefeed.
Kotlin_io_Console_println0();
#endif
}
void Kotlin_io_Console_println0() {
konan::consoleWriteUtf8("\n", 1);
}
OBJ_GETTER0(Kotlin_io_Console_readLine) {
char data[4096];
if (konan::consoleReadUtf8(data, sizeof(data)) < 0) {
RETURN_OBJ(nullptr);
}
RETURN_RESULT_OF(CreateStringFromCString, data);
}
} // extern "C"
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2018 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_DOUBLECONVERSIONS_H
#define RUNTIME_DOUBLECONVERSIONS_H
#include "Types.h"
namespace {
typedef union {
KLong l;
KDouble d;
} DoubleAlias;
typedef union {
KInt i;
KFloat f;
} FloatAlias;
}
inline KDouble bitsToDouble(KLong bits) {
DoubleAlias alias;
alias.l = bits;
return alias.d;
}
inline KLong doubleToBits(KDouble value) {
DoubleAlias alias;
alias.d = value;
return alias.l;
}
inline KFloat bitsToFloat(KInt bits) {
FloatAlias alias;
alias.i = bits;
return alias.f;
}
inline KInt floatToBits(KFloat value) {
FloatAlias alias;
alias.f = value;
return alias.i;
}
extern "C" KInt doubleUpper(KDouble value);
extern "C" KInt doubleLower(KDouble value);
#endif // RUNTIME_DOUBLECONVERSIONS_H
@@ -0,0 +1,347 @@
/*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <exception>
#include <unistd.h>
#if KONAN_NO_EXCEPTIONS
#define OMIT_BACKTRACE 1
#endif
#ifndef OMIT_BACKTRACE
#if USE_GCC_UNWIND
// GCC unwinder for backtrace.
#include <unwind.h>
#else
// Glibc backtrace() function.
#include <execinfo.h>
#endif
#endif // OMIT_BACKTRACE
#include "KAssert.h"
#include "Exceptions.h"
#include "ExecFormat.h"
#include "Memory.h"
#include "Natives.h"
#include "KString.h"
#include "SourceInfo.h"
#include "Types.h"
#include "Utils.h"
#include "ObjCExceptions.h"
namespace {
// RuntimeUtils.kt
extern "C" void ReportUnhandledException(KRef throwable);
extern "C" void ExceptionReporterLaunchpad(KRef reporter, KRef throwable);
KRef currentUnhandledExceptionHook = nullptr;
int32_t currentUnhandledExceptionHookLock = 0;
int32_t currentUnhandledExceptionHookCookie = 0;
#if USE_GCC_UNWIND
struct Backtrace {
Backtrace(int count, int skip) : index(0), skipCount(skip) {
uint32_t size = count - skipCount;
if (size < 0) {
size = 0;
}
auto result = AllocArrayInstance(theNativePtrArrayTypeInfo, size, arrayHolder.slot());
// TODO: throw cached OOME?
RuntimeCheck(result != nullptr, "Cannot create backtrace array");
}
void setNextElement(_Unwind_Ptr element) {
Kotlin_NativePtrArray_set(obj(), index++, (KNativePtr) element);
}
ObjHeader* obj() { return arrayHolder.obj(); }
int index;
int skipCount;
ObjHolder arrayHolder;
};
_Unwind_Reason_Code depthCountCallback(
struct _Unwind_Context * context, void* arg) {
int* result = reinterpret_cast<int*>(arg);
(*result)++;
return _URC_NO_REASON;
}
_Unwind_Reason_Code unwindCallback(
struct _Unwind_Context* context, void* arg) {
Backtrace* backtrace = reinterpret_cast<Backtrace*>(arg);
if (backtrace->skipCount > 0) {
backtrace->skipCount--;
return _URC_NO_REASON;
}
#if (__MINGW32__ || __MINGW64__)
_Unwind_Ptr address = _Unwind_GetRegionStart(context);
#else
_Unwind_Ptr address = _Unwind_GetIP(context);
#endif
backtrace->setNextElement(address);
return _URC_NO_REASON;
}
#endif
THREAD_LOCAL_VARIABLE bool disallowSourceInfo = false;
SourceInfo getSourceInfo(KConstRef stackTrace, int index) {
return disallowSourceInfo
? SourceInfo { .fileName = nullptr, .lineNumber = -1, .column = -1 }
: Kotlin_getSourceInfo(*PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), index));
}
} // namespace
// TODO: this implementation is just a hack, e.g. the result is inexact;
// however it is better to have an inexact stacktrace than not to have any.
NO_INLINE OBJ_GETTER0(Kotlin_getCurrentStackTrace) {
#if OMIT_BACKTRACE
return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT);
#else
// Skips first 2 elements as irrelevant: this function and primary Throwable constructor.
constexpr int kSkipFrames = 2;
#if USE_GCC_UNWIND
int depth = 0;
_Unwind_Backtrace(depthCountCallback, &depth);
Backtrace result(depth, kSkipFrames);
if (result.obj()->array()->count_ > 0) {
_Unwind_Backtrace(unwindCallback, &result);
}
RETURN_OBJ(result.obj());
#else
const int maxSize = 32;
void* buffer[maxSize];
int size = backtrace(buffer, maxSize);
if (size < kSkipFrames)
return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT);
ObjHolder resultHolder;
ObjHeader* result = AllocArrayInstance(theNativePtrArrayTypeInfo, size - kSkipFrames, resultHolder.slot());
for (int index = kSkipFrames; index < size; ++index) {
Kotlin_NativePtrArray_set(result, index - kSkipFrames, buffer[index]);
}
RETURN_OBJ(result);
#endif
#endif // !OMIT_BACKTRACE
}
OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
#if OMIT_BACKTRACE
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT);
ObjHolder holder;
CreateStringFromCString("<UNIMPLEMENTED>", holder.slot());
UpdateHeapRef(ArrayAddressOfElementAt(result->array(), 0), holder.obj());
return result;
#else
uint32_t size = stackTrace->array()->count_;
ObjHolder resultHolder;
ObjHeader* strings = AllocArrayInstance(theArrayTypeInfo, size, resultHolder.slot());
#if USE_GCC_UNWIND
for (uint32_t index = 0; index < size; ++index) {
KNativePtr address = Kotlin_NativePtrArray_get(stackTrace, index);
char symbol[512];
if (!AddressToSymbol((const void*) address, symbol, sizeof(symbol))) {
// Make empty string:
symbol[0] = '\0';
}
char line[512];
konan::snprintf(line, sizeof(line) - 1, "%s (%p)", symbol, (void*)(intptr_t)address);
ObjHolder holder;
CreateStringFromCString(line, holder.slot());
UpdateHeapRef(ArrayAddressOfElementAt(strings->array(), index), holder.obj());
}
#else
if (size > 0) {
char **symbols = backtrace_symbols(PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), 0), size);
RuntimeCheck(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
for (uint32_t index = 0; index < size; ++index) {
auto sourceInfo = getSourceInfo(stackTrace, index);
const char* symbol = symbols[index];
const char* result;
char line[1024];
if (sourceInfo.fileName != nullptr) {
if (sourceInfo.lineNumber != -1) {
konan::snprintf(line, sizeof(line) - 1, "%s (%s:%d:%d)",
symbol, sourceInfo.fileName, sourceInfo.lineNumber, sourceInfo.column);
} else {
konan::snprintf(line, sizeof(line) - 1, "%s (%s:<unknown>)", symbol, sourceInfo.fileName);
}
result = line;
} else {
result = symbol;
}
ObjHolder holder;
CreateStringFromCString(result, holder.slot());
UpdateHeapRef(ArrayAddressOfElementAt(strings->array(), index), holder.obj());
}
// Not konan::free. Used to free memory allocated in backtrace_symbols where malloc is used.
free(symbols);
}
#endif
RETURN_OBJ(strings);
#endif // !OMIT_BACKTRACE
}
void ThrowException(KRef exception) {
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
"Throwing something non-throwable");
#if KONAN_NO_EXCEPTIONS
PrintThrowable(exception);
RuntimeCheck(false, "Exceptions unsupported");
#else
throw ExceptionObjHolder(exception);
#endif
}
OBJ_GETTER(Kotlin_setUnhandledExceptionHook, KRef hook) {
RETURN_RESULT_OF(SwapHeapRefLocked,
&currentUnhandledExceptionHook, currentUnhandledExceptionHook, hook, &currentUnhandledExceptionHookLock,
&currentUnhandledExceptionHookCookie);
}
void OnUnhandledException(KRef throwable) {
ObjHolder handlerHolder;
auto* handler = SwapHeapRefLocked(&currentUnhandledExceptionHook, currentUnhandledExceptionHook, nullptr,
&currentUnhandledExceptionHookLock, &currentUnhandledExceptionHookCookie, handlerHolder.slot());
if (handler == nullptr) {
ReportUnhandledException(throwable);
} else {
ExceptionReporterLaunchpad(handler, throwable);
}
}
namespace {
class {
/**
* Timeout 5 sec for concurrent (second) terminate attempt to give a chance the first one to finish.
* If the terminate handler hangs for 5 sec it is probably fatally broken, so let's do abnormal _Exit in that case.
*/
unsigned int timeoutSec = 5;
int terminatingFlag = 0;
public:
template <class Fun> RUNTIME_NORETURN void operator()(Fun block) {
if (compareAndSet(&terminatingFlag, 0, 1)) {
block();
// block() is supposed to be NORETURN, otherwise go to normal abort()
konan::abort();
} else {
sleep(timeoutSec);
// We come here when another terminate handler hangs for 5 sec, that looks fatally broken. Go to forced exit now.
}
_Exit(EXIT_FAILURE); // force exit
}
} concurrentTerminateWrapper;
//! Process exception hook (if any) or just printStackTrace + write crash log
void processUnhandledKotlinException(KRef throwable) {
OnUnhandledException(throwable);
#if KONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG
ReportBacktraceToIosCrashLog(throwable);
#endif
}
} // namespace
RUNTIME_NORETURN void TerminateWithUnhandledException(KRef throwable) {
concurrentTerminateWrapper([=]() {
processUnhandledKotlinException(throwable);
konan::abort();
});
}
// Some libstdc++-based targets has limited support for std::current_exception and other C++11 functions.
// This restriction can be lifted later when toolchains will be updated.
#if KONAN_HAS_CXX11_EXCEPTION_FUNCTIONS
namespace {
class TerminateHandler {
// In fact, it's safe to call my_handler directly from outside: it will do the job and then invoke original handler,
// even if it has not been initialized yet. So one may want to make it public and/or not the class member
RUNTIME_NORETURN static void kotlinHandler() {
concurrentTerminateWrapper([]() {
if (auto currentException = std::current_exception()) {
try {
std::rethrow_exception(currentException);
} catch (ExceptionObjHolder& e) {
processUnhandledKotlinException(e.obj());
konan::abort();
} catch (...) {
// Not a Kotlin exception - call default handler
instance().queuedHandler_();
}
}
// Come here in case of direct terminate() call or unknown exception - go to default terminate handler.
instance().queuedHandler_();
});
}
using QH = __attribute__((noreturn)) void(*)();
QH queuedHandler_;
/// Use machinery like Meyers singleton to provide thread safety
TerminateHandler()
: queuedHandler_((QH)std::set_terminate(kotlinHandler)) {}
static TerminateHandler& instance() {
static TerminateHandler singleton [[clang::no_destroy]];
return singleton;
}
// Copy, move and assign would be safe, but not much useful, so let's delete all (rule of 5)
TerminateHandler(const TerminateHandler&) = delete;
TerminateHandler(TerminateHandler&&) = delete;
TerminateHandler& operator=(const TerminateHandler&) = delete;
TerminateHandler& operator=(TerminateHandler&&) = delete;
// Dtor might be in use to restore original handler. However, consequent install
// will not reconstruct handler anyway, so let's keep dtor deleted to avoid confusion.
~TerminateHandler() = delete;
public:
/// First call will do the job, all consequent will do nothing.
static void install() {
instance(); // Use side effect of warming up
}
};
} // anon namespace
// Use one public function to limit access to the class declaration
void SetKonanTerminateHandler() {
TerminateHandler::install();
}
#else // KONAN_OBJC_INTEROP
void SetKonanTerminateHandler() {
// Nothing to do.
}
#endif // KONAN_OBJC_INTEROP
void DisallowSourceInfo() {
disallowSourceInfo = true;
}
@@ -0,0 +1,77 @@
/*
* 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_EXCEPTIONS_H
#define RUNTIME_EXCEPTIONS_H
#include "Types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Returns current stacktrace as Array<String>.
OBJ_GETTER0(Kotlin_getCurrentStackTrace);
OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace);
OBJ_GETTER(Kotlin_setUnhandledExceptionHook, KRef hook);
// Throws arbitrary exception.
void ThrowException(KRef exception);
void OnUnhandledException(KRef throwable);
RUNTIME_NORETURN void TerminateWithUnhandledException(KRef exception);
void SetKonanTerminateHandler();
// The functions below are implemented in Kotlin (at package kotlin.native.internal).
// Throws null pointer exception. Context is evaluated from caller's address.
void RUNTIME_NORETURN ThrowNullPointerException();
// Throws array index out of bounds exception.
// Context is evaluated from caller's address.
void RUNTIME_NORETURN ThrowArrayIndexOutOfBoundsException();
// Throws class cast exception.
void RUNTIME_NORETURN ThrowClassCastException(const ObjHeader* instance, const TypeInfo* type_info);
// Throws arithmetic exception.
void RUNTIME_NORETURN ThrowArithmeticException();
// Throws number format exception.
void RUNTIME_NORETURN ThrowNumberFormatException();
// Throws out of memory error.
void RUNTIME_NORETURN ThrowOutOfMemoryError();
// Throws not implemented error.
void RUNTIME_NORETURN ThrowNotImplementedError();
// Throws character coding exception (used in UTF8/UTF16 conversions).
void RUNTIME_NORETURN ThrowCharacterCodingException();
void RUNTIME_NORETURN ThrowIllegalArgumentException();
void RUNTIME_NORETURN ThrowIllegalStateException();
void RUNTIME_NORETURN ThrowInvalidMutabilityException(KConstRef where);
void RUNTIME_NORETURN ThrowIncorrectDereferenceException();
void RUNTIME_NORETURN ThrowIllegalObjectSharingException(KConstNativePtr typeInfo, KConstNativePtr address);
void RUNTIME_NORETURN ThrowFreezingException(KRef toFreeze, KRef blocker);
// Prints out message of Throwable.
void PrintThrowable(KRef);
#ifdef __cplusplus
} // extern "C"
#endif
// It's not always safe to extract SourceInfo during unhandled exception termination.
void DisallowSourceInfo();
#endif // RUNTIME_NAMES_H
@@ -0,0 +1,333 @@
/*
* 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.
*/
#include "ExecFormat.h"
#include "Types.h"
#if USE_ELF_SYMBOLS
#include <dlfcn.h>
#include <elf.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
#include "KAssert.h"
namespace {
#if !defined(ELFSIZE)
#error "Define ELFSIZE to 32 or 64"
#endif
#if ELFSIZE == 32
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#elif ELFSIZE == 64
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#else
#error "Impossible ELFSIZE"
#endif
struct SymRecord {
Elf_Sym* symtabBegin;
Elf_Sym* symtabEnd;
char* strtab;
};
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.
Elf_Ehdr* findElfHeader() {
int fd = open("/proc/self/exe", O_RDONLY);
if (fd < 0) return nullptr;
struct stat fd_stat;
if (fstat(fd, &fd_stat) < 0) return nullptr;
void* result = mmap(nullptr, fd_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (result == MAP_FAILED) return nullptr;
return (Elf_Ehdr*)result;
}
void initSymbols() {
RuntimeAssert(symbols == nullptr, "Init twice");
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");
char* mapAddress = (char*)ehdr;
Elf_Shdr* shdr = (Elf_Shdr*)(mapAddress + ehdr->e_shoff);
for (int i = 0; i < ehdr->e_shnum; i++) {
if (shdr[i].sh_type == SHT_SYMTAB) { // Static symbol table.
SymRecord record;
record.symtabBegin = (Elf_Sym*)(mapAddress + shdr[i].sh_offset);
record.symtabEnd = (Elf_Sym*)((char*)record.symtabBegin + shdr[i].sh_size);
record.strtab = (char *)(mapAddress + shdr[shdr[i].sh_link].sh_offset);
symbols->push_back(record);
}
if (shdr[i].sh_type == SHT_DYNSYM) { // Dynamic symbol table.
SymRecord record;
record.symtabBegin = (Elf_Sym*)(mapAddress + shdr[i].sh_offset);
record.symtabEnd = (Elf_Sym*)((char*)record.symtabBegin + shdr[i].sh_size);
record.strtab = (char*)(mapAddress + shdr[shdr[i].sh_link].sh_offset);
symbols->push_back(record);
}
}
}
const char* addressToSymbol(const void* address) {
if (address == nullptr) return nullptr;
// First, look up in dynamically loaded symbols.
Dl_info info;
if (dladdr(address, &info) != 0 && info.dli_sname != nullptr) {
return info.dli_sname;
}
// Otherwise, consult symbol table of the file.
if (symbols == nullptr) {
initSymbols();
}
unsigned long addressValue = (unsigned long)address;
for (auto record : *symbols) {
auto begin = record.symtabBegin;
auto end = record.symtabEnd;
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];
}
begin++;
}
}
return nullptr;
}
} // namespace
extern "C" bool AddressToSymbol(const void* address, char* resultBuffer, size_t resultBufferSize) {
const char* result = addressToSymbol(address);
if (result == nullptr) {
return false;
} else {
strncpy(resultBuffer, result, resultBufferSize);
resultBuffer[resultBufferSize - 1] = '\0';
return true;
}
}
#elif USE_PE_COFF_SYMBOLS
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include "KAssert.h"
namespace {
static void* mapModuleFile(HMODULE hModule) {
DWORD bufferLength = 64;
wchar_t* buffer = nullptr;
for (;;) {
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) {
break;
}
const int MAX_BUFFER_SIZE = 32768; // Max path length + 1.
if (res == bufferLength && bufferLength < MAX_BUFFER_SIZE) {
// Buffer is too small, continue:
bufferLength *= 2;
continue;
}
// Invalid result.
konanFreeMemory(buffer);
return nullptr;
}
HANDLE hFile = CreateFileW(
/* lpFileName = */ buffer,
/* dwDesiredAccess = */ GENERIC_READ,
/* dwShareMode = */ FILE_SHARE_READ,
/* lpSecurityAttributes = */ nullptr,
/* dwCreationDisposition = */ OPEN_EXISTING,
/* dwFlagsAndAttributes = */ FILE_ATTRIBUTE_NORMAL,
/* hTemplateFile = */ nullptr
);
konanFreeMemory(buffer);
if (hFile == INVALID_HANDLE_VALUE) {
// Can't open module file.
return nullptr;
}
HANDLE hFileMappingObject = CreateFileMapping(
hFile,
/* lpAttributes = */ nullptr,
/* flProtect = */ PAGE_READONLY,
/* dwMaximumSizeHigh = */ 0,
/* dwMaximumSizeLow = */ 0,
/* lpName = */ nullptr
);
if (hFileMappingObject == nullptr) {
// Can't create file mapping.
CloseHandle(hFile);
return nullptr;
}
LPVOID mapAddress = MapViewOfFile(
hFileMappingObject,
/* dwDesiredAccess = */ FILE_MAP_READ,
/* dwFileOffsetHigh = */ 0,
/* dwFileOffsetLow = */ 0,
/* dwNumberOfBytesToMap = */ 0
);
if (mapAddress == nullptr) {
// Failed to create map view.
CloseHandle(hFileMappingObject);
CloseHandle(hFile);
return nullptr;
}
return mapAddress;
}
class SymbolTable {
private:
char* imageBase = nullptr;
IMAGE_SECTION_HEADER* sectionHeaders = nullptr;
IMAGE_SYMBOL* symbols = nullptr;
DWORD numberOfSymbols = 0;
// Note: it doesn't free resources yet.
~SymbolTable() {}
static const int SYMBOL_SHORT_NAME_LENGTH = 8;
void getSymbolName(IMAGE_SYMBOL* sym, char* resultBuffer, size_t resultBufferSize) {
if (sym->N.Name.Short != 0) {
// ShortName is not zero-terminated if its length exactly equals SYMBOL_SHORT_NAME_LENGTH.
// Copy it to the buffer and zero-terminate explicitly:
size_t bytesToCopy = SYMBOL_SHORT_NAME_LENGTH;
if (bytesToCopy > resultBufferSize - 1) bytesToCopy = resultBufferSize - 1;
memcpy(resultBuffer, sym->N.ShortName, bytesToCopy);
resultBuffer[bytesToCopy] = '\0';
} else {
const char* strTable = (const char*)(symbols + numberOfSymbols);
const char* result = strTable + sym->N.Name.Long;
strncpy(resultBuffer, result, resultBufferSize);
resultBuffer[resultBufferSize - 1] = '\0';
}
}
const void* getSymbolAddress(IMAGE_SYMBOL* symbol) {
IMAGE_SECTION_HEADER* sectionHeader = &sectionHeaders[symbol->SectionNumber - 1];
return (const void*)(imageBase + sectionHeader->VirtualAddress + symbol->Value);
}
IMAGE_SYMBOL* findFunctionSymbol(const void* address) {
for (DWORD i = 0; i < numberOfSymbols; ++i) {
IMAGE_SYMBOL* symbol = &symbols[i];
if (symbol->Type == 0x20 && address == getSymbolAddress(symbol)) {
return symbol;
}
}
return nullptr;
}
public:
explicit SymbolTable(HMODULE hModule) {
imageBase = (char*)hModule;
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)imageBase;
RuntimeAssert(dosHeader->e_magic == IMAGE_DOS_SIGNATURE, "PE executable e_magic mismatch");
IMAGE_NT_HEADERS* ntHeaders = (IMAGE_NT_HEADERS*)(imageBase + dosHeader->e_lfanew);
RuntimeAssert(ntHeaders->Signature == IMAGE_NT_SIGNATURE, "PE executable NT signature mismatch");
IMAGE_FILE_HEADER* fileHeader = &ntHeaders->FileHeader;
sectionHeaders = (IMAGE_SECTION_HEADER*)(((char*)(fileHeader + 1)) + fileHeader->SizeOfOptionalHeader);
if (fileHeader->PointerToSymbolTable == 0 || fileHeader->NumberOfSymbols == 0) {
// No symbols.
return;
}
// Symbol table doesn't get mapped to the memory, so we have to load it ourselves:
char* mappedModuleFile = (char*)mapModuleFile(hModule);
if (mappedModuleFile != nullptr) {
symbols = (IMAGE_SYMBOL*)(mappedModuleFile + fileHeader->PointerToSymbolTable);
numberOfSymbols = fileHeader->NumberOfSymbols;
}
}
bool functionAddressToSymbol(const void* address, char* resultBuffer, size_t resultBufferSize) {
IMAGE_SYMBOL* symbol = findFunctionSymbol(address);
if (symbol == nullptr) {
return false;
} else {
getSymbolName(symbol, resultBuffer, resultBufferSize);
return true;
}
}
};
SymbolTable* theExeSymbolTable = nullptr;
} // namespace
extern "C" bool AddressToSymbol(const void* address, char* resultBuffer, size_t resultBufferSize) {
if (theExeSymbolTable == nullptr) {
// Note: do not protecting the lazy initialization by critical sections for simplicity;
// this doesn't have any serious consequences.
HMODULE hModule = nullptr;
int rv = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&AddressToSymbol), &hModule);
RuntimeAssert(rv != 0, "GetModuleHandleExW fails");
theExeSymbolTable = konanConstructInstance<SymbolTable>(hModule);
}
return theExeSymbolTable->functionAddressToSymbol(address, resultBuffer, resultBufferSize);
}
#else
extern "C" bool AddressToSymbol(const void* address, char* resultBuffer, size_t resultBufferSize) {
return false;
}
#endif // USE_ELF_SYMBOLS
@@ -0,0 +1,28 @@
/*
* 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_EXECFORMAT_H
#define RUNTIME_EXECFORMAT_H
#include <stddef.h>
extern "C" {
bool AddressToSymbol(const void* address, char* resultBuffer, size_t resultBufferSize);
} // extern "C"
#endif // RUNTIME_EXECFORMAT_H
@@ -0,0 +1,45 @@
/*
* 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.
*/
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include "Alloc.h"
#include "Memory.h"
#include "MemorySharedRefs.hpp"
#include "Types.h"
extern "C" {
KNativePtr Kotlin_Interop_createStablePointer(KRef any) {
KRefSharedHolder* holder = konanConstructInstance<KRefSharedHolder>();
holder->init(any);
return holder;
}
void Kotlin_Interop_disposeStablePointer(KNativePtr pointer) {
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
holder->dispose();
konanDestructInstance(holder);
}
OBJ_GETTER(Kotlin_Interop_derefStablePointer, KNativePtr pointer) {
KRefSharedHolder* holder = reinterpret_cast<KRefSharedHolder*>(pointer);
RETURN_OBJ(holder->ref<ErrorPolicy::kThrow>());
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2018 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.
*/
#include "Porting.h"
#include "Types.h"
typedef KInt Arena;
typedef KInt Object;
typedef KInt Pointer;
#ifndef KONAN_WASM
extern "C" {
// These functions are implemented in JS file for WASM and are not available on other platforms.
RUNTIME_NORETURN Arena Konan_js_allocateArena() {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
RUNTIME_NORETURN void Konan_js_freeArena(Arena arena) {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
RUNTIME_NORETURN void Konan_js_pushIntToArena(Arena arena, KInt value) {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
RUNTIME_NORETURN KInt Konan_js_getInt(Arena arena,
Object obj,
Pointer propertyPtr,
KInt propertyLen) {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
RUNTIME_NORETURN KInt Konan_js_getProperty(Arena arena,
Object obj,
Pointer propertyPtr,
KInt propertyLen) {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
RUNTIME_NORETURN void Konan_js_setFunction(Arena arena,
Object obj,
Pointer propertyName,
KInt propertyLength,
KInt function) {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
RUNTIME_NORETURN void Konan_js_setString(Arena arena,
Object obj,
Pointer propertyName,
KInt propertyLength,
Pointer stringPtr,
KInt stringLength) {
RuntimeAssert(false, "JavaScript interop is disabled");
konan::abort();
}
}; // extern "C"
#endif // #ifndef KONAN_WASM
@@ -0,0 +1,29 @@
/*
* 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.
*/
#include "KAssert.h"
#include "Porting.h"
void RuntimeAssertFailed(const char* location, const char* message) {
// TODO: produce stacktrace and such.
char buf[1024];
if (location != nullptr)
konan::snprintf(buf, sizeof(buf), "%s: runtime assert: %s\n", location, message);
else
konan::snprintf(buf, sizeof(buf), "runtime assert: %s\n", message);
konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf)));
konan::abort();
}
@@ -0,0 +1,51 @@
/*
* 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_ASSERT_H
#define RUNTIME_ASSERT_H
#include "Common.h"
// To avoid cluttering optimized code with asserts, they could be turned off.
#define KONAN_ENABLE_ASSERT 1
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* message);
// During codegeneration we set this constant to 1 or 0 to allow bitcode optimizer
// to get rid of code behind condition.
extern "C" const int KonanNeedDebugInfo;
#if KONAN_ENABLE_ASSERT
// Use RuntimeAssert() in internal state checks, which could be ignored in production.
#define RuntimeAssert(condition, message) \
if (KonanNeedDebugInfo && (!(condition))) { \
RuntimeAssertFailed( __FILE__ ":" TOSTRING(__LINE__), message); \
}
#else
#define RuntimeAssert(condition, message)
#endif
// Use RuntimeCheck() in runtime checks that could fail due to external condition and shall lead
// to program termination. Never compiled out.
#define RuntimeCheck(condition, message) \
if (!(condition)) { \
RuntimeAssertFailed(nullptr, message); \
}
#endif // RUNTIME_ASSERT_H
@@ -0,0 +1,97 @@
/*
* 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_KDEBUG_H
#define RUNTIME_KDEBUG_H
#include "Common.h"
#include "Memory.h"
#include "Types.h"
#include "TypeInfo.h"
#ifndef KONAN_NO_DEBUG_API
#ifdef __cplusplus
extern "C" {
#endif
// PLEASE READ: please do not alter signatures of the existing functions, and when adding
// the new function please do not forget to add new functions into the debug operations list.
// Get memory buffer where debugger can put data in Konan app process.
RUNTIME_USED RUNTIME_WEAK
char* Konan_DebugBuffer();
// Same, but runtime-specific.
RUNTIME_USED RUNTIME_WEAK
char* Konan_DebugBufferWithObject(KRef obj);
// Get size of memory buffer where debugger can put data in Konan app process.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugBufferSize();
// Same, but runtime-specific.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugBufferSizeWithObject(KRef obj);
// Put string representation of an object to the provided buffer.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int32_t bufferSize);
// Print to console string representation of an object.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugPrint(KRef obj);
// Returns 1 if obj refers to an array, string or binary blob and 0 otherwise.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugIsArray(KRef obj);
// Returns number of fields in an objects, or elements in an array.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugGetFieldCount(KRef obj);
// Compute type of field or an array element at the index, or 0, if incorrect,
// see Konan_RuntimeType.
RUNTIME_USED RUNTIME_WEAK
int32_t Konan_DebugGetFieldType(KRef obj, int32_t index);
// Compute address of field or an array element at the index, or null, if incorrect.
RUNTIME_USED RUNTIME_WEAK
void* Konan_DebugGetFieldAddress(KRef obj, int32_t index);
// Compute address of field or an array element at the index, or null, if incorrect.
RUNTIME_USED RUNTIME_WEAK
const char* Konan_DebugGetFieldName(KRef obj, int32_t index);
// Returns name of type.
RUNTIME_USED RUNTIME_WEAK
const char* Konan_DebugGetTypeName(KRef obj);
/**
* Given an object finds debugger interface operation suitable for manipulation with this object.
* Important for cases where multiple K/N runtimes coexist in the same address space and debugger
* doesn't know which debug operation to use on particular instance.
*/
RUNTIME_USED RUNTIME_WEAK
void* Konan_DebugGetOperation(KRef obj, /* Konan_DebugOperation */ int32_t operation);
#ifdef __cplusplus
}
#endif
#endif // !KONAN_NO_DEBUG_API
#endif // RUNTIME_KDEBUG_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,57 @@
/*
* 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_KSTRING_H
#define RUNTIME_KSTRING_H
#include "Common.h"
#include "Memory.h"
#include "Types.h"
#include "TypeInfo.h"
#ifdef __cplusplus
extern "C" {
#endif
OBJ_GETTER(CreateStringFromCString, const char* cstring);
OBJ_GETTER(CreateStringFromUtf8, const char* utf8, uint32_t lengthBytes);
char* CreateCStringFromString(KConstRef kstring);
void DisposeCString(char* cstring);
#ifdef __cplusplus
}
#endif
template <typename T>
int binarySearchRange(const T* array, int arrayLength, T needle) {
int bottom = 0;
int top = arrayLength - 1;
int middle = -1;
T value = 0;
while (bottom <= top) {
middle = (bottom + top) / 2;
value = array[middle];
if (needle > value)
bottom = middle + 1;
else if (needle == value)
return middle;
else
top = middle - 1;
}
return middle - (needle < value ? 1 : 0);
}
#endif // RUNTIME_KSTRING_H
@@ -0,0 +1,580 @@
/*
* Copyright 2010-2018 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.
*/
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include "DoubleConversions.h"
#include "Exceptions.h"
#include "KotlinMath.h"
#include "ReturnSlot.h"
#include "Types.h"
#if (__MINGW32__ || __MINGW64__)
#define KONAN_NEED_ASINH_ACOSH 1
#else
#define KONAN_NEED_ASINH_ACOSH 0
#endif
#if KONAN_NEED_ASINH_ACOSH
namespace {
// MinGW's implmenetation of asinh/acosh function returns NaN for large arguments so we use another implementation.
// Both implementations derived from boost special math functions and are also used by Kotlin/JVM.
// Copyright Eric Ford & Hubert Holin 2001.
constexpr KDouble LN2 = 0.69314718055994530942;
constexpr KDouble SQRT2 = 1.41421356237309504880;
KDouble taylor_2_bound = sqrt(DBL_EPSILON);
KDouble taylor_n_bound = sqrt(taylor_2_bound);
KDouble upper_taylor_2_bound = 1.0 / taylor_2_bound;
KDouble upper_taylor_n_bound = 1.0 / taylor_n_bound;
KDouble custom_asinh(KDouble x) {
if (x >= +taylor_n_bound) {
if (x > upper_taylor_n_bound) {
if (x > upper_taylor_2_bound) {
// approximation by laurent series in 1/x at 0+ order from -1 to 0
return log(x) + LN2;
} else {
// approximation by laurent series in 1/x at 0+ order from -1 to 1
return log(x * 2 + (1.0 / (x * 2)));
}
} else {
return log(x + sqrt(x * x + 1));
}
} else if (x <= -taylor_n_bound) {
return -custom_asinh(-x);
} else {
// approximation by taylor series in x at 0 up to order 2
KDouble result = x;
if (fabs(x) >= taylor_2_bound) {
// approximation by taylor series in x at 0 up to order 4
result -= (x * x * x) / 6;
}
return result;
}
}
KDouble custom_acosh(KDouble x) {
if (x < 1) {
return NAN;
} else if (x > upper_taylor_2_bound) {
// approximation by laurent series in 1/x at 0+ order from -1 to 0
return log(x) + LN2;
} else if (x - 1 >= taylor_n_bound) {
return log(x + sqrt(x * x - 1));
} else {
KDouble y = sqrt(x - 1);
// approximation by taylor series in y at 0 up to order 2
KDouble result = y;
if (y >= taylor_2_bound) {
// approximation by taylor series in y at 0 up to order 4
result -= (y * y * y) / 12;
}
return SQRT2 * result;
}
}
}
#endif
extern "C" {
#ifndef KONAN_NO_MATH // We have a platform math library. Call its math functions.
#ifndef KONAN_WASM // Use libm.
// region Double math.
KDouble Kotlin_math_sin(KDouble x) { return sin(x); }
KDouble Kotlin_math_cos(KDouble x) { return cos(x); }
KDouble Kotlin_math_tan(KDouble x) { return tan(x); }
KDouble Kotlin_math_asin(KDouble x) { return asin(x); }
KDouble Kotlin_math_acos(KDouble x) { return acos(x); }
KDouble Kotlin_math_atan(KDouble x) { return atan(x); }
KDouble Kotlin_math_atan2(KDouble y, KDouble x) { return atan2(y, x); }
KDouble Kotlin_math_sinh(KDouble x) { return sinh(x); }
KDouble Kotlin_math_cosh(KDouble x) { return cosh(x); }
KDouble Kotlin_math_tanh(KDouble x) { return tanh(x); }
KDouble Kotlin_math_asinh(KDouble x) {
#if (KONAN_NEED_ASINH_ACOSH)
return custom_asinh(x);
#else
return asinh(x);
#endif
}
KDouble Kotlin_math_acosh(KDouble x) {
#if (KONAN_NEED_ASINH_ACOSH)
return custom_acosh(x);
#else
return acosh(x);
#endif
}
KDouble Kotlin_math_atanh(KDouble x) { return atanh(x); }
KDouble Kotlin_math_hypot(KDouble x, KDouble y) {
if (isinf(x) || isinf(y)) return INFINITY;
if (isnan(x) || isnan(y)) return NAN;
return hypot(x, y);
}
KDouble Kotlin_math_sqrt(KDouble x) { return sqrt(x); }
KDouble Kotlin_math_exp(KDouble x) { return exp(x); }
KDouble Kotlin_math_expm1(KDouble x) { return expm1(x); }
KDouble Kotlin_math_ln(KDouble x) { return log(x); }
KDouble Kotlin_math_log10(KDouble x) { return log10(x); }
KDouble Kotlin_math_log2(KDouble x) { return log2(x); }
KDouble Kotlin_math_ln1p(KDouble x) { return log1p(x); }
KDouble Kotlin_math_ceil(KDouble x) { return ceil(x); }
KDouble Kotlin_math_floor(KDouble x) { return floor(x); }
KDouble Kotlin_math_round(KDouble x) { return rint(x); }
KDouble Kotlin_math_abs(KDouble x) { return fabs(x); }
// extensions
KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) {
// Kotlin corner cases
if (x == 0.0 || x == -0.0) return 1.0;
if (isinf(x) && (thiz == 1.0 || thiz == -1.0)) return NAN;
return pow(thiz, x);
}
KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) { return remainder(thiz, divisor); }
KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) { return copysign(thiz, sign); }
KDouble Kotlin_math_Double_nextUp(KDouble thiz) { return nextafter(thiz, HUGE_VAL); }
KDouble Kotlin_math_Double_nextDown(KDouble thiz) { return nextafter(thiz, -HUGE_VAL); }
KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) {
return (thiz == to) ? to : nextafter(thiz, to);
}
KBoolean Kotlin_math_Double_signBit(KDouble thiz) { return signbit(thiz) != 0; }
// endregion
// region Float math.
KFloat Kotlin_math_sinf(KFloat x) { return sinf(x); }
KFloat Kotlin_math_cosf(KFloat x) { return cosf(x); }
KFloat Kotlin_math_tanf(KFloat x) { return tanf(x); }
KFloat Kotlin_math_asinf(KFloat x) { return asinf(x); }
KFloat Kotlin_math_acosf(KFloat x) { return acosf(x); }
KFloat Kotlin_math_atanf(KFloat x) { return atanf(x); }
KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { return atan2f(y, x); }
KFloat Kotlin_math_sinhf(KFloat x) { return sinhf(x); }
KFloat Kotlin_math_coshf(KFloat x) { return coshf(x); }
KFloat Kotlin_math_tanhf(KFloat x) { return tanhf(x); }
KFloat Kotlin_math_asinhf(KFloat x) {
#if (KONAN_NEED_ASINH_ACOSH)
return (KFloat)custom_asinh((KDouble)x);
#else
return asinhf(x);
#endif
}
KFloat Kotlin_math_acoshf(KFloat x) {
#if (KONAN_NEED_ASINH_ACOSH)
return (KFloat)custom_acosh((KDouble)x);
#else
return acoshf(x);
#endif
}
KFloat Kotlin_math_atanhf(KFloat x) { return atanhf(x); }
KFloat Kotlin_math_hypotf(KFloat x, KFloat y) {
if (isinf(x) || isinf(y)) return INFINITY;
if (isnan(x) || isnan(y)) return NAN;
return hypotf(x, y);
}
KFloat Kotlin_math_sqrtf(KFloat x) { return sqrtf(x); }
KFloat Kotlin_math_expf(KFloat x) { return expf(x); }
KFloat Kotlin_math_expm1f(KFloat x) { return expm1f(x); }
KFloat Kotlin_math_lnf(KFloat x) { return logf(x); }
KFloat Kotlin_math_log10f(KFloat x) { return log10f(x); }
KFloat Kotlin_math_log2f(KFloat x) { return log2f(x); }
KFloat Kotlin_math_ln1pf(KFloat x) { return log1pf(x); }
KFloat Kotlin_math_ceilf(KFloat x) { return ceilf(x); }
KFloat Kotlin_math_floorf(KFloat x) { return floorf(x); }
KFloat Kotlin_math_roundf(KFloat x) { return rintf(x); }
KFloat Kotlin_math_absf(KFloat x) { return fabsf(x); }
// extensions
KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) {
// Kotlin corner cases
if (x == 0.0 || x == -0.0) return 1.0;
if (isinf(x) && (thiz == 1.0 || thiz == -1.0)) return NAN;
return powf(thiz, x);
}
KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) { return remainderf(thiz, divisor); }
KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) { return copysignf(thiz, sign); }
KFloat Kotlin_math_Float_nextUp(KFloat thiz) { return nextafterf(thiz, HUGE_VALF); }
KFloat Kotlin_math_Float_nextDown(KFloat thiz) { return nextafterf(thiz, -HUGE_VALF); }
KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) {
return (thiz == to) ? to : nextafterf(thiz, to);
}
KBoolean Kotlin_math_Float_signBit(KFloat thiz) { return signbit(thiz) != 0; }
// endregion
// region Integer math.
KInt Kotlin_math_absi(KInt x) { return labs(x); }
KLong Kotlin_math_absl(KLong x) { return llabs(x); }
// endregion
#else // KONAN_WASM defined. Use JS math implementation.
#define RETURN_RESULT_OF_JS_CALL(call, doubleArg) { \
call(doubleUpper(doubleArg), doubleLower(doubleArg)); \
return ReturnSlot_getDouble(); \
}
#define RETURN_RESULT_OF_JS_CALL2(call, doubleArg1, doubleArg2) { \
call(doubleUpper(doubleArg1), \
doubleLower(doubleArg1), \
doubleUpper(doubleArg2), \
doubleLower(doubleArg2)); \
return ReturnSlot_getDouble(); \
}
KDouble Kotlin_math_sin(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_sin, x); }
KDouble Kotlin_math_cos(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_cos, x); }
KDouble Kotlin_math_tan(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_tan, x); }
KDouble Kotlin_math_asin(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_asin, x); }
KDouble Kotlin_math_acos(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_acos, x); }
KDouble Kotlin_math_atan(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_atan, x); }
KDouble Kotlin_math_sinh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_sinh, x); }
KDouble Kotlin_math_cosh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_cosh, x); }
KDouble Kotlin_math_tanh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_tanh, x); }
KDouble Kotlin_math_asinh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_asinh, x); }
KDouble Kotlin_math_acosh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_acosh, x); }
KDouble Kotlin_math_atanh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_atanh, x); }
KDouble Kotlin_math_sqrt(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_sqrt, x); }
KDouble Kotlin_math_exp(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_exp, x); }
KDouble Kotlin_math_expm1(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_expm1, x); }
KDouble Kotlin_math_ln(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log, x); }
KDouble Kotlin_math_log10(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log10, x); }
KDouble Kotlin_math_log2(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log2, x); }
KDouble Kotlin_math_ln1p(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log1p, x); }
KDouble Kotlin_math_ceil(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_ceil, x); }
KDouble Kotlin_math_floor(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_floor, x); }
KDouble Kotlin_math_round(KDouble x) {
if (fmod(x, 0.5) != 0.0) {
RETURN_RESULT_OF_JS_CALL(knjs__Math_round, x);
}
KDouble f = floor(x);
return (fmod(f, 2) == 0.0) ? f : ceil(x);
}
KDouble Kotlin_math_abs(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_abs, x); }
KDouble Kotlin_math_atan2(KDouble y, KDouble x) { RETURN_RESULT_OF_JS_CALL2(knjs__Math_atan2, y, x); }
KDouble Kotlin_math_hypot(KDouble x, KDouble y) { RETURN_RESULT_OF_JS_CALL2(knjs__Math_hypot, x, y); }
// extensions
KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) { RETURN_RESULT_OF_JS_CALL2(knjs__Math_pow, thiz, x); }
KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) {
if (isnan(thiz) || isnan(divisor) || isinf(thiz) || divisor == 0.0) {
return NAN;
}
if (!isinf(thiz) && isinf(divisor)) {
return thiz;
}
KDouble rounded = Kotlin_math_round(thiz / divisor);
return thiz - rounded * divisor;
}
KDouble Kotlin_math_Double_nextUp(KDouble thiz) {
if (isnan(thiz) || thiz == HUGE_VAL) {
return thiz;
}
if (thiz == 0.0) {
return DBL_TRUE_MIN;
}
return bitsToDouble(doubleToBits(thiz) + (thiz > 0 ? 1 : -1));
}
KDouble Kotlin_math_Double_nextDown(KDouble thiz) {
if (isnan(thiz) || thiz == -HUGE_VAL) {
return thiz;
}
if (thiz == 0.0) {
return -DBL_TRUE_MIN;
}
return bitsToDouble(doubleToBits(thiz) - (thiz > 0 ? 1 : -1));
}
KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) {
if (isnan(thiz) || isnan(to)) {
return NAN;
}
if (to > thiz) {
return Kotlin_math_Double_nextUp(thiz);
}
if (to < thiz) {
return Kotlin_math_Double_nextDown(thiz);
}
// thiz == to
return to;
}
KBoolean Kotlin_math_Double_signBit(KDouble thiz) {
return (doubleToBits(thiz) & (KLong) 1 << 63) != 0;
}
KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) {
bool oldSign = Kotlin_math_Double_signBit(thiz);
bool newSign = Kotlin_math_Double_signBit(sign);
return (oldSign == newSign) ? thiz : -thiz;
}
// endregion
// region Float math.
KFloat Kotlin_math_sinf(KFloat x) { return (KFloat)Kotlin_math_sin (x); }
KFloat Kotlin_math_cosf(KFloat x) { return (KFloat)Kotlin_math_cos (x); }
KFloat Kotlin_math_tanf(KFloat x) { return (KFloat)Kotlin_math_tan (x); }
KFloat Kotlin_math_asinf(KFloat x) { return (KFloat)Kotlin_math_asin (x); }
KFloat Kotlin_math_acosf(KFloat x) { return (KFloat)Kotlin_math_acos (x); }
KFloat Kotlin_math_atanf(KFloat x) { return (KFloat)Kotlin_math_atan (x); }
KFloat Kotlin_math_sinhf(KFloat x) { return (KFloat)Kotlin_math_sinh (x); }
KFloat Kotlin_math_coshf(KFloat x) { return (KFloat)Kotlin_math_cosh (x); }
KFloat Kotlin_math_tanhf(KFloat x) { return (KFloat)Kotlin_math_tanh (x); }
KFloat Kotlin_math_asinhf(KFloat x) { return (KFloat)Kotlin_math_asinh (x); }
KFloat Kotlin_math_acoshf(KFloat x) { return (KFloat)Kotlin_math_acosh (x); }
KFloat Kotlin_math_atanhf(KFloat x) { return (KFloat)Kotlin_math_atanh (x); }
KFloat Kotlin_math_sqrtf(KFloat x) { return (KFloat)Kotlin_math_sqrt (x); }
KFloat Kotlin_math_expf(KFloat x) { return (KFloat)Kotlin_math_exp (x); }
KFloat Kotlin_math_expm1f(KFloat x) { return (KFloat)Kotlin_math_expm1 (x); }
KFloat Kotlin_math_lnf(KFloat x) { return (KFloat)Kotlin_math_ln (x); }
KFloat Kotlin_math_log10f(KFloat x) { return (KFloat)Kotlin_math_log10 (x); }
KFloat Kotlin_math_log2f(KFloat x) { return (KFloat)Kotlin_math_log2 (x); }
KFloat Kotlin_math_ln1pf(KFloat x) { return (KFloat)Kotlin_math_ln1p (x); }
KFloat Kotlin_math_ceilf(KFloat x) { return (KFloat)Kotlin_math_ceil (x); }
KFloat Kotlin_math_floorf(KFloat x) { return (KFloat)Kotlin_math_floor (x); }
KFloat Kotlin_math_roundf(KFloat x) { return (KFloat)Kotlin_math_round (x); }
KFloat Kotlin_math_absf(KFloat x) { return (KFloat)Kotlin_math_abs (x); }
KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { return (KFloat)Kotlin_math_atan2(y, x); }
KFloat Kotlin_math_hypotf(KFloat x, KFloat y) { return (KFloat)Kotlin_math_hypot(x, y); }
// extensions
KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) { return (KFloat)Kotlin_math_Double_pow(thiz, x); }
KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) {
return (KFloat)Kotlin_math_Double_IEEErem(thiz, divisor);
}
KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) {
return (KFloat)Kotlin_math_Double_withSign(thiz, sign);
}
KFloat Kotlin_math_Float_nextUp(KFloat thiz) {
if (isnan(thiz) || thiz == HUGE_VALF) {
return thiz;
}
if (thiz == 0.0) {
return FLT_TRUE_MIN;
}
return bitsToFloat(floatToBits(thiz) + (thiz > 0 ? 1 : -1));
}
KFloat Kotlin_math_Float_nextDown(KFloat thiz) {
if (isnan(thiz) || thiz == -HUGE_VALF) {
return thiz;
}
if (thiz == 0.0) {
return -FLT_TRUE_MIN;
}
return bitsToFloat(floatToBits(thiz) - (thiz > 0 ? 1 : -1));
}
KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) {
if (isnan(thiz) || isnan(to)) {
return NAN;
}
if (to > thiz) {
return Kotlin_math_Float_nextUp(thiz);
}
if (to < thiz) {
return Kotlin_math_Float_nextDown(thiz);
}
// thiz == to
return to;
}
KBoolean Kotlin_math_Float_signBit(KFloat thiz) { return Kotlin_math_Double_signBit(thiz); }
// endregion
// region Integer math
KInt Kotlin_math_absi(KInt x) { return (x >= 0) ? x : -x; }
KLong Kotlin_math_absl(KLong x) { return (x >= 0) ? x : -x; }
#endif // #ifndef KONAN_WASM
#else // KONAN_NO_MATH defined - we have no patform math library. Throw NotImplementedError from math functions.
namespace {
RUNTIME_NORETURN void NotImplemented() {
ThrowNotImplementedError();
}
} // namespace
KDouble Kotlin_math_sin(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_cos(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_tan(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_asin(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_acos(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_atan(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_atan2(KDouble y, KDouble x) { NotImplemented(); }
KDouble Kotlin_math_sinh(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_cosh(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_tanh(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_asinh(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_acosh(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_atanh(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_hypot(KDouble x, KDouble y) { NotImplemented(); }
KDouble Kotlin_math_sqrt(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_exp(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_expm1(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_ln(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_log10(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_log2(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_ln1p(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_ceil(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_floor(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_round(KDouble x) { NotImplemented(); }
KDouble Kotlin_math_abs(KDouble x) { NotImplemented(); }
// extensions
KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) { NotImplemented(); }
KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) { NotImplemented(); }
KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) { NotImplemented(); }
KDouble Kotlin_math_Double_nextUp(KDouble thiz) { NotImplemented(); }
KDouble Kotlin_math_Double_nextDown(KDouble thiz) { NotImplemented(); }
KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) { NotImplemented(); }
KBoolean Kotlin_math_Double_signBit(KDouble thiz) { NotImplemented(); }
// endregion
// region Float math.
KFloat Kotlin_math_sinf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_cosf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_tanf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_asinf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_acosf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_atanf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { NotImplemented(); }
KFloat Kotlin_math_sinhf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_coshf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_tanhf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_asinhf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_acoshf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_atanhf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_hypotf(KFloat x, KFloat y) { NotImplemented(); }
KFloat Kotlin_math_sqrtf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_expf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_expm1f(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_lnf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_log10f(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_log2f(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_ln1pf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_ceilf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_floorf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_roundf(KFloat x) { NotImplemented(); }
KFloat Kotlin_math_absf(KFloat x) { NotImplemented(); }
// extensions
KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) { NotImplemented(); }
KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) { NotImplemented(); }
KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) { NotImplemented(); }
KFloat Kotlin_math_Float_nextUp(KFloat thiz) { NotImplemented(); }
KFloat Kotlin_math_Float_nextDown(KFloat thiz) { NotImplemented(); }
KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) { NotImplemented(); }
KBoolean Kotlin_math_Float_signBit(KFloat thiz) { NotImplemented(); }
// endregion
// region Integer math
KInt Kotlin_math_absi(KInt x) { NotImplemented(); }
KInt Kotlin_math_mini(KInt a, KInt b) { NotImplemented(); }
KInt Kotlin_math_maxi(KInt a, KInt b) { NotImplemented(); }
KLong Kotlin_math_absl(KLong x) { NotImplemented(); }
KLong Kotlin_math_minl(KLong a, KLong b) { NotImplemented(); }
KLong Kotlin_math_maxl(KLong a, KLong b) { NotImplemented(); }
#endif // #ifndef KONAN_NO_MATH
} // extern "C"
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2018 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_KOTLINMATH_H
#define RUNTIME_KOTLINMATH_H
#include "Types.h"
#ifdef KONAN_WASM
extern "C" {
// TODO: consider auto-generating this header file.
// Bridges for JS math.
void knjs__Math_abs(KInt xUpper, KInt xLower);
void knjs__Math_acos(KInt xUpper, KInt xLower);
void knjs__Math_acosh(KInt xUpper, KInt xLower);
void knjs__Math_asin(KInt xUpper, KInt xLower);
void knjs__Math_asinh(KInt xUpper, KInt xLower);
void knjs__Math_atan(KInt xUpper, KInt xLower);
void knjs__Math_atan2(KInt yUpper, KInt yLower, KInt xUpper, KInt xLower);
void knjs__Math_atanh(KInt xUpper, KInt xLower);
void knjs__Math_cbrt(KInt xUpper, KInt xLower);
void knjs__Math_ceil(KInt xUpper, KInt xLower);
void knjs__Math_clz32(KInt xUpper, KInt xLower);
void knjs__Math_cos(KInt xUpper, KInt xLower);
void knjs__Math_cosh(KInt xUpper, KInt xLower);
void knjs__Math_exp(KInt xUpper, KInt xLower);
void knjs__Math_expm1(KInt xUpper, KInt xLower);
void knjs__Math_floor(KInt xUpper, KInt xLower);
void knjs__Math_fround(KInt xUpper, KInt xLower);
void knjs__Math_log(KInt xUpper, KInt xLower);
void knjs__Math_log1p(KInt xUpper, KInt xLower);
void knjs__Math_log10(KInt xUpper, KInt xLower);
void knjs__Math_log2(KInt xUpper, KInt xLower);
void knjs__Math_round(KInt xUpper, KInt xLower);
void knjs__Math_sign(KInt xUpper, KInt xLower);
void knjs__Math_sin(KInt xUpper, KInt xLower);
void knjs__Math_sinh(KInt xUpper, KInt xLower);
void knjs__Math_sqrt(KInt xUpper, KInt xLower);
void knjs__Math_tan(KInt xUpper, KInt xLower);
void knjs__Math_tanh(KInt xUpper, KInt xLower);
void knjs__Math_trunc(KInt xUpper, KInt xLower);
void knjs__Math_hypot(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower);
void knjs__Math_max(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower);
void knjs__Math_min(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower);
void knjs__Math_pow(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower);
}
#endif // KONAN_WASM
#endif // RUNTIME_KOTLINMATH_H
+321
View File
@@ -0,0 +1,321 @@
/*
* Copyright 2010-2018 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_MEMORY_H
#define RUNTIME_MEMORY_H
#include "KAssert.h"
#include "Common.h"
#include "TypeInfo.h"
#include "Atomic.h"
#include "PointerBits.h"
typedef enum {
// Must match to permTag() in Kotlin.
OBJECT_TAG_PERMANENT_CONTAINER = 1 << 0,
OBJECT_TAG_NONTRIVIAL_CONTAINER = 1 << 1,
// Keep in sync with immTypeInfoMask in Kotlin.
OBJECT_TAG_MASK = (1 << 2) - 1
} ObjectTag;
struct ArrayHeader;
struct MetaObjHeader;
// Header of every object.
struct ObjHeader {
TypeInfo* typeInfoOrMeta_;
const TypeInfo* type_info() const {
return clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK)->typeInfo_;
}
bool has_meta_object() const {
auto* typeInfoOrMeta = clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK);
return (typeInfoOrMeta != typeInfoOrMeta->typeInfo_);
}
MetaObjHeader* meta_object() {
return has_meta_object() ?
reinterpret_cast<MetaObjHeader*>(clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK)) :
createMetaObject(&typeInfoOrMeta_);
}
ALWAYS_INLINE ObjHeader** GetWeakCounterLocation();
#ifdef KONAN_OBJC_INTEROP
ALWAYS_INLINE void* GetAssociatedObject();
ALWAYS_INLINE void** GetAssociatedObjectLocation();
ALWAYS_INLINE void SetAssociatedObject(void* obj);
#endif
inline bool local() const {
unsigned bits = getPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK);
return (bits & (OBJECT_TAG_PERMANENT_CONTAINER | OBJECT_TAG_NONTRIVIAL_CONTAINER)) ==
(OBJECT_TAG_PERMANENT_CONTAINER | OBJECT_TAG_NONTRIVIAL_CONTAINER);
}
// Unsafe cast to ArrayHeader. Use carefully!
ArrayHeader* array() { return reinterpret_cast<ArrayHeader*>(this); }
const ArrayHeader* array() const { return reinterpret_cast<const ArrayHeader*>(this); }
inline bool permanent() const {
return hasPointerBits(typeInfoOrMeta_, OBJECT_TAG_PERMANENT_CONTAINER);
}
static MetaObjHeader* createMetaObject(TypeInfo** location);
static void destroyMetaObject(TypeInfo** location);
};
// Header of value type array objects. Keep layout in sync with that of object header.
struct ArrayHeader {
TypeInfo* typeInfoOrMeta_;
const TypeInfo* type_info() const {
return clearPointerBits(typeInfoOrMeta_, OBJECT_TAG_MASK)->typeInfo_;
}
ObjHeader* obj() { return reinterpret_cast<ObjHeader*>(this); }
const ObjHeader* obj() const { return reinterpret_cast<const ObjHeader*>(this); }
// Elements count. Element size is stored in instanceSize_ field of TypeInfo, negated.
uint32_t count_;
};
ALWAYS_INLINE bool isFrozen(const ObjHeader* obj);
ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj);
ALWAYS_INLINE bool isShareable(const ObjHeader* obj);
class ForeignRefManager;
typedef ForeignRefManager* ForeignRefContext;
#ifdef __cplusplus
extern "C" {
#endif
#define OBJ_RESULT __result__
#define OBJ_GETTER0(name) ObjHeader* name(ObjHeader** OBJ_RESULT)
#define OBJ_GETTER(name, ...) ObjHeader* name(__VA_ARGS__, ObjHeader** OBJ_RESULT)
#define RETURN_OBJ(value) { ObjHeader* __obj = value; \
UpdateReturnRef(OBJ_RESULT, __obj); \
return __obj; }
#define RETURN_RESULT_OF0(name) { \
ObjHeader* __obj = name(OBJ_RESULT); \
return __obj; \
}
#define RETURN_RESULT_OF(name, ...) { \
ObjHeader* __result = name(__VA_ARGS__, OBJ_RESULT); \
return __result; \
}
struct MemoryState;
MemoryState* InitMemory();
void DeinitMemory(MemoryState*);
void RestoreMemory(MemoryState*);
//
// Object allocation.
//
// Allocation can happen in either GLOBAL, FRAME or ARENA scope. Depending on that,
// Alloc* or ArenaAlloc* is called. Regular alloc means allocation happens in the heap,
// and each object gets its individual container. Otherwise, allocator uses aux slot in
// an implementation-defined manner, current behavior is to keep arena pointer there.
// Arena containers are not reference counted, and is explicitly freed when leaving
// its owner frame.
// Escape analysis algorithm is the provider of information for decision on exact aux slot
// selection, and comes from upper bound esteemation of object lifetime.
//
OBJ_GETTER(AllocInstance, const TypeInfo* type_info) RUNTIME_NOTHROW;
OBJ_GETTER(AllocArrayInstance, const TypeInfo* type_info, int32_t elements);
OBJ_GETTER(InitInstance,
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
OBJ_GETTER(InitSharedInstance,
ObjHeader** location, const TypeInfo* typeInfo, void (*ctor)(ObjHeader*));
//
// Object reference management.
//
// Reference management scheme we use assumes significant degree of flexibility, so that
// one could implement either pure reference counting scheme, or tracing collector without
// much ado.
// Most important primitive is Update*Ref() API, which modifies location to use new
// object reference. In pure reference counted scheme it will check old value,
// decrement reference, increment counter on the new value, and store it into the field.
// In tracing collector-like scheme, only field updates counts, and all other operations are
// essentially no-ops.
//
// On codegeneration phase we adopt following approaches:
// - every stack frame has several slots, holding object references (allRefs)
// - those are known by compiler (and shall be grouped together)
// - it keeps all locally allocated objects in such slot
// - all local variables keeping an object also allocate a slot
// - most manipulations on objects happens in SSA variables and do no affect slots
// - exception handlers knowns slot locations for every function, and can update references
// in intermediate frames when throwing
//
// Controls the current memory model, is compile-time constant.
extern const bool IsStrictMemoryModel;
// Sets stack location.
void SetStackRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Sets heap location.
void SetHeapRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Zeroes heap location.
void ZeroHeapRef(ObjHeader** location) RUNTIME_NOTHROW;
// Zeroes an array.
void ZeroArrayRefs(ArrayHeader* array) RUNTIME_NOTHROW;
// Zeroes stack location.
void ZeroStackRef(ObjHeader** location) RUNTIME_NOTHROW;
// Updates stack location.
void UpdateStackRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Updates heap/static data location.
void UpdateHeapRef(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Updates location if it is null, atomically.
void UpdateHeapRefIfNull(ObjHeader** location, const ObjHeader* object) RUNTIME_NOTHROW;
// Updates reference in return slot.
void UpdateReturnRef(ObjHeader** returnSlot, const ObjHeader* object) RUNTIME_NOTHROW;
// Compares and swaps reference with taken lock.
OBJ_GETTER(SwapHeapRefLocked,
ObjHeader** location, ObjHeader* expectedValue, ObjHeader* newValue, int32_t* spinlock,
int32_t* cookie) RUNTIME_NOTHROW;
// Sets reference with taken lock.
void SetHeapRefLocked(ObjHeader** location, ObjHeader* newValue, int32_t* spinlock,
int32_t* cookie) RUNTIME_NOTHROW;
// Reads reference with taken lock.
OBJ_GETTER(ReadHeapRefLocked, ObjHeader** location, int32_t* spinlock, int32_t* cookie) RUNTIME_NOTHROW;
// Called on frame enter, if it has object slots.
void EnterFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
// Called on frame leave, if it has object slots.
void LeaveFrame(ObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
// Clears object subgraph references from memory subsystem, and optionally
// checks if subgraph referenced by given root is disjoint from the rest of
// object graph, i.e. no external references exists.
bool ClearSubgraphReferences(ObjHeader* root, bool checked) RUNTIME_NOTHROW;
// Creates stable pointer out of the object.
void* CreateStablePointer(ObjHeader* obj) RUNTIME_NOTHROW;
// Disposes stable pointer to the object.
void DisposeStablePointer(void* pointer) RUNTIME_NOTHROW;
// Translate stable pointer to object reference.
OBJ_GETTER(DerefStablePointer, void*) RUNTIME_NOTHROW;
// Move stable pointer ownership.
OBJ_GETTER(AdoptStablePointer, void*) RUNTIME_NOTHROW;
// Check mutability state.
void MutationCheck(ObjHeader* obj);
void CheckLifetimesConstraint(ObjHeader* obj, ObjHeader* pointee) RUNTIME_NOTHROW;
// Freeze object subgraph.
void FreezeSubgraph(ObjHeader* obj);
// Ensure this object shall block freezing.
void EnsureNeverFrozen(ObjHeader* obj);
// Add TLS object storage, called by the generated code.
void AddTLSRecord(MemoryState* memory, void** key, int size) RUNTIME_NOTHROW;
// Clear TLS object storage, called by the generated code.
void ClearTLSRecord(MemoryState* memory, void** key) RUNTIME_NOTHROW;
// Lookup element in TLS object storage.
ObjHeader** LookupTLS(void** key, int index) RUNTIME_NOTHROW;
// APIs for the async GC.
void GC_RegisterWorker(void* worker) RUNTIME_NOTHROW;
void GC_UnregisterWorker(void* worker) RUNTIME_NOTHROW;
void GC_CollectorCallback(void* worker) RUNTIME_NOTHROW;
bool Kotlin_Any_isShareable(ObjHeader* thiz);
void PerformFullGC() RUNTIME_NOTHROW;
bool TryAddHeapRef(const ObjHeader* object);
void ReleaseHeapRef(const ObjHeader* object) RUNTIME_NOTHROW;
void ReleaseHeapRefNoCollect(const ObjHeader* object) RUNTIME_NOTHROW;
ForeignRefContext InitLocalForeignRef(ObjHeader* object);
ForeignRefContext InitForeignRef(ObjHeader* object);
void DeinitForeignRef(ObjHeader* object, ForeignRefContext context);
bool IsForeignRefAccessible(ObjHeader* object, ForeignRefContext context);
// Should be used when reference is read from a possibly shared variable,
// and there's nothing else keeping the object alive.
void AdoptReferenceFromSharedVariable(ObjHeader* object);
#ifdef __cplusplus
}
#endif
struct FrameOverlay {
void* arena;
FrameOverlay* previous;
// As they go in pair, sizeof(FrameOverlay) % sizeof(void*) == 0 is always held.
int32_t parameters;
int32_t count;
};
// Class holding reference to an object, holding object during C++ scope.
class ObjHolder {
public:
ObjHolder() : obj_(nullptr) {
EnterFrame(frame(), 0, sizeof(*this)/sizeof(void*));
}
explicit ObjHolder(const ObjHeader* obj) {
EnterFrame(frame(), 0, sizeof(*this)/sizeof(void*));
::SetStackRef(slot(), obj);
}
~ObjHolder() {
LeaveFrame(frame(), 0, sizeof(*this)/sizeof(void*));
}
ObjHeader* obj() { return obj_; }
const ObjHeader* obj() const { return obj_; }
ObjHeader** slot() {
return &obj_;
}
void clear() { ::ZeroStackRef(&obj_); }
private:
ObjHeader** frame() { return reinterpret_cast<ObjHeader**>(&frame_); }
FrameOverlay frame_;
ObjHeader* obj_;
};
//! TODO Follow the Rule of Zero to prevent dangling on unintented copy ctor
class ExceptionObjHolder {
public:
explicit ExceptionObjHolder(const ObjHeader* obj) {
::SetHeapRef(&obj_, obj);
}
~ExceptionObjHolder() {
ZeroHeapRef(&obj_);
}
ObjHeader* obj() { return obj_; }
const ObjHeader* obj() const { return obj_; }
private:
ObjHeader* obj_;
};
#endif // RUNTIME_MEMORY_H
@@ -0,0 +1,216 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "Exceptions.h"
#include "MemorySharedRefs.hpp"
#include "Runtime.h"
#include "Types.h"
extern "C" {
// Returns a string describing object at `address` of type `typeInfo`.
OBJ_GETTER(DescribeObjectForDebugging, KConstNativePtr typeInfo, KConstNativePtr address);
} // extern "C"
namespace {
inline bool isForeignRefAccessible(ObjHeader* object, ForeignRefContext context) {
// If runtime has not been initialized on this thread, then the object is either unowned or shared.
// In the former case initialized runtime is required to throw exceptions
// in the latter case -- to provide proper execution context for caller.
Kotlin_initRuntimeIfNeeded();
return IsForeignRefAccessible(object, context);
}
RUNTIME_NORETURN inline void throwIllegalSharingException(ObjHeader* object) {
// TODO: add some info about the context.
// Note: retrieving 'type_info()' is supposed to be correct even for unowned object.
ThrowIllegalObjectSharingException(object->type_info(), object);
}
RUNTIME_NORETURN inline void terminateWithIllegalSharingException(ObjHeader* object) {
#if KONAN_NO_EXCEPTIONS
// This will terminate.
throwIllegalSharingException(object);
#else
try {
throwIllegalSharingException(object);
} catch (...) {
// A trick to terminate with unhandled exception. This will print a stack trace
// and write to iOS crash log.
std::terminate();
}
#endif
}
template <ErrorPolicy errorPolicy>
bool ensureRefAccessible(ObjHeader* object, ForeignRefContext context) {
static_assert(errorPolicy != ErrorPolicy::kIgnore, "Must've been handled by specialization");
if (isForeignRefAccessible(object, context)) {
return true;
}
switch (errorPolicy) {
case ErrorPolicy::kDefaultValue:
return false;
case ErrorPolicy::kThrow:
throwIllegalSharingException(object);
case ErrorPolicy::kTerminate:
terminateWithIllegalSharingException(object);
}
}
template <>
bool ensureRefAccessible<ErrorPolicy::kIgnore>(ObjHeader* object, ForeignRefContext context) {
return true;
}
} // namespace
void KRefSharedHolder::initLocal(ObjHeader* obj) {
RuntimeAssert(obj != nullptr, "must not be null");
context_ = InitLocalForeignRef(obj);
obj_ = obj;
}
void KRefSharedHolder::init(ObjHeader* obj) {
RuntimeAssert(obj != nullptr, "must not be null");
context_ = InitForeignRef(obj);
obj_ = obj;
}
template <ErrorPolicy errorPolicy>
ObjHeader* KRefSharedHolder::ref() const {
if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
return nullptr;
}
AdoptReferenceFromSharedVariable(obj_);
return obj_;
}
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kDefaultValue>() const;
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kThrow>() const;
template ObjHeader* KRefSharedHolder::ref<ErrorPolicy::kTerminate>() const;
void KRefSharedHolder::dispose() const {
if (obj_ == nullptr) {
// To handle the case when it is not initialized. See [KotlinMutableSet/Dictionary dealloc].
return;
}
DeinitForeignRef(obj_, context_);
}
OBJ_GETTER0(KRefSharedHolder::describe) const {
// Note: retrieving 'type_info()' is supposed to be correct even for unowned object.
RETURN_RESULT_OF(DescribeObjectForDebugging, obj_->type_info(), obj_);
}
void BackRefFromAssociatedObject::initAndAddRef(ObjHeader* obj) {
RuntimeAssert(obj != nullptr, "must not be null");
obj_ = obj;
// Generally a specialized addRef below:
context_ = InitForeignRef(obj);
refCount = 1;
}
template <ErrorPolicy errorPolicy>
void BackRefFromAssociatedObject::addRef() {
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
if (atomicAdd(&refCount, 1) == 1) {
if (obj_ == nullptr) return; // E.g. after [detach].
// There are no references to the associated object itself, so Kotlin object is being passed from Kotlin,
// and it is owned therefore.
ensureRefAccessible<errorPolicy>(obj_, context_); // TODO: consider removing explicit verification.
// Foreign reference has already been deinitialized (see [releaseRef]).
// Create a new one:
context_ = InitForeignRef(obj_);
}
}
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kThrow>();
template void BackRefFromAssociatedObject::addRef<ErrorPolicy::kTerminate>();
template <ErrorPolicy errorPolicy>
bool BackRefFromAssociatedObject::tryAddRef() {
static_assert(errorPolicy != ErrorPolicy::kDefaultValue, "Cannot use default return value here");
if (obj_ == nullptr) return false; // E.g. after [detach].
// Suboptimal but simple:
ensureRefAccessible<errorPolicy>(obj_, context_);
ObjHeader* obj = obj_;
if (!TryAddHeapRef(obj)) return false;
RuntimeAssert(isForeignRefAccessible(obj_, context_), "Cannot be inaccessible because of the check above");
// TODO: This is a very weird way to ask for "unsafe" addRef.
addRef<ErrorPolicy::kIgnore>();
ReleaseHeapRefNoCollect(obj); // Balance TryAddHeapRef.
// TODO: consider optimizing for non-shared objects.
return true;
}
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kThrow>();
template bool BackRefFromAssociatedObject::tryAddRef<ErrorPolicy::kTerminate>();
void BackRefFromAssociatedObject::releaseRef() {
ForeignRefContext context = context_;
if (atomicAdd(&refCount, -1) == 0) {
if (obj_ == nullptr) return; // E.g. after [detach].
// Note: by this moment "subsequent" addRef may have already happened and patched context_.
// So use the value loaded before refCount update:
DeinitForeignRef(obj_, context);
// From this moment [context] is generally a dangling pointer.
// This is handled in [IsForeignRefAccessible] and [addRef].
}
}
void BackRefFromAssociatedObject::detach() {
RuntimeAssert(atomicGet(&refCount) == 0, "unexpected refCount")
obj_ = nullptr; // Handled in addRef/tryAddRef/releaseRef/ref.
}
template <ErrorPolicy errorPolicy>
ObjHeader* BackRefFromAssociatedObject::ref() const {
RuntimeAssert(obj_ != nullptr, "no valid Kotlin object found");
if (!ensureRefAccessible<errorPolicy>(obj_, context_)) {
return nullptr;
}
AdoptReferenceFromSharedVariable(obj_);
return obj_;
}
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kDefaultValue>() const;
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kThrow>() const;
template ObjHeader* BackRefFromAssociatedObject::ref<ErrorPolicy::kTerminate>() const;
extern "C" {
RUNTIME_NOTHROW void KRefSharedHolder_initLocal(KRefSharedHolder* holder, ObjHeader* obj) {
holder->initLocal(obj);
}
RUNTIME_NOTHROW void KRefSharedHolder_init(KRefSharedHolder* holder, ObjHeader* obj) {
holder->init(obj);
}
RUNTIME_NOTHROW void KRefSharedHolder_dispose(const KRefSharedHolder* holder) {
holder->dispose();
}
RUNTIME_NOTHROW ObjHeader* KRefSharedHolder_ref(const KRefSharedHolder* holder) {
return holder->ref<ErrorPolicy::kTerminate>();
}
} // extern "C"
@@ -0,0 +1,72 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_MEMORYSHAREDREFS_HPP
#define RUNTIME_MEMORYSHAREDREFS_HPP
#include <type_traits>
#include "Memory.h"
// TODO: Generalize for uses outside this file.
enum class ErrorPolicy {
kIgnore, // Ignore any errors. (i.e. unsafe mode)
kDefaultValue, // Return the default value from the function when an error happens.
kThrow, // Throw a Kotlin exception when an error happens. The exact exception is chosen by the callee.
kTerminate, // Terminate immediately when an error happens.
};
class KRefSharedHolder {
public:
void initLocal(ObjHeader* obj);
void init(ObjHeader* obj);
// Error if called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
ObjHeader* ref() const;
void dispose() const;
OBJ_GETTER0(describe) const;
private:
ObjHeader* obj_;
ForeignRefContext context_;
};
static_assert(std::is_trivially_destructible<KRefSharedHolder>::value,
"KRefSharedHolder destructor is not guaranteed to be called.");
class BackRefFromAssociatedObject {
public:
void initAndAddRef(ObjHeader* obj);
// Error if refCount is zero and it's called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
void addRef();
// Error if called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
bool tryAddRef();
void releaseRef();
void detach();
// Error if called from the wrong worker with non-frozen obj_.
template <ErrorPolicy errorPolicy>
ObjHeader* ref() const;
private:
ObjHeader* obj_; // May be null before [initAndAddRef] or after [detach].
ForeignRefContext context_;
volatile int refCount;
};
static_assert(std::is_trivially_destructible<BackRefFromAssociatedObject>::value,
"BackRefFromAssociatedObject destructor is not guaranteed to be called.");
#endif // RUNTIME_MEMORYSHAREDREFS_HPP
@@ -0,0 +1,84 @@
/*
* 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.
*/
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <type_traits>
#include "KAssert.h"
#include "Exceptions.h"
#include "Memory.h"
#include "Natives.h"
#include "Types.h"
extern "C" {
// Any.kt
KBoolean Kotlin_Any_equals(KConstRef thiz, KConstRef other) {
return thiz == other;
}
KInt Kotlin_Any_hashCode(KConstRef thiz) {
// Here we will use different mechanism for stable hashcode, using meta-objects
// if moving collector will be used.
return reinterpret_cast<uintptr_t>(thiz);
}
OBJ_GETTER(Kotlin_getStackTraceStrings, KConstRef stackTrace) {
RETURN_RESULT_OF(GetStackTraceStrings, stackTrace);
}
// TODO: consider handling it with compiler magic instead.
OBJ_GETTER0(Kotlin_native_internal_undefined) {
RETURN_OBJ(nullptr);
}
void* Kotlin_interop_malloc(KLong size, KInt align) {
if (size < 0 || static_cast<std::make_unsigned<decltype(size)>::type>(size) > std::numeric_limits<size_t>::max()) {
return nullptr;
}
RuntimeAssert(align > 0, "Unsupported alignment");
RuntimeAssert((align & (align - 1)) == 0, "Alignment must be power of two");
void* result = konan::calloc_aligned(1, size, align);
if ((reinterpret_cast<uintptr_t>(result) & (align - 1)) != 0) {
// Unaligned!
RuntimeAssert(false, "unsupported alignment");
}
return result;
}
void Kotlin_interop_free(void* ptr) {
konan::free(ptr);
}
void Kotlin_system_exitProcess(KInt status) {
konan::exit(status);
}
const void* Kotlin_Any_getTypeInfo(KConstRef obj) {
return obj->type_info();
}
void Kotlin_CPointer_CopyMemory(KNativePtr to, KNativePtr from, KInt count) {
memcpy(to, from, count);
}
} // extern "C"
@@ -0,0 +1,97 @@
/*
* 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_NATIVES_H
#define RUNTIME_NATIVES_H
#include "Types.h"
#include "Exceptions.h"
#include "Memory.h"
constexpr size_t alignUp(size_t size, size_t alignment) {
return (size + alignment - 1) & ~(alignment - 1);
}
template <typename T>
inline T* AddressOfElementAt(ArrayHeader* obj, KInt index) {
int8_t* body = reinterpret_cast<int8_t*>(obj) + alignUp(sizeof(ArrayHeader), alignof(T));
return reinterpret_cast<T*>(body) + index;
}
template <typename T>
inline const T* AddressOfElementAt(const ArrayHeader* obj, KInt index) {
const int8_t* body = reinterpret_cast<const int8_t*>(obj) + alignUp(sizeof(ArrayHeader), alignof(T));
return reinterpret_cast<const T*>(body) + index;
}
// Optimized versions not accessing type info.
inline KByte* ByteArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KByte>(obj, index);
}
inline const KByte* ByteArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KByte>(obj, index);
}
inline KChar* CharArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KChar>(obj, index);
}
inline const KChar* CharArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KChar>(obj, index);
}
inline KInt* IntArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KInt>(obj, index);
}
inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KInt>(obj, index);
}
// Consider aligning of base to sizeof(T).
template <typename T>
inline T* PrimitiveArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return AddressOfElementAt<T>(obj, index);
}
template <typename T>
inline const T* PrimitiveArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return AddressOfElementAt<T>(obj, index);
}
inline KRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KRef>(obj, index);
}
inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KRef>(obj, index);
}
#ifdef __cplusplus
extern "C" {
#endif
OBJ_GETTER0(TheEmptyString);
void Kotlin_io_Console_println0();
void Kotlin_NativePtrArray_set(KRef thiz, KInt index, KNativePtr value);
KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index);
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_NATIVES_H
@@ -0,0 +1,125 @@
#if KONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG
#include <dlfcn.h>
#include <inttypes.h>
#include <mach-o/loader.h>
#include <CoreFoundation/CFRunLoop.h>
#include "Natives.h"
#include "ObjCExceptions.h"
#include "Types.h"
extern "C" OBJ_GETTER(Kotlin_Throwable_getStackTrace, KRef throwable);
static void writeStackTraceToBuffer(KRef throwable, char* buffer, unsigned long bufferSize) {
if (bufferSize < 2) return;
ObjHolder stackTraceHolder;
ArrayHeader* stackTrace = Kotlin_Throwable_getStackTrace(throwable, stackTraceHolder.slot())->array();
char* bufferPointer = buffer;
unsigned long remainingBytes = bufferSize;
*(bufferPointer++) = '(';
--remainingBytes;
for (uint32_t index = 0; index < stackTrace->count_; ++index) {
KNativePtr ptr = *PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace, index);
int bytes = snprintf(bufferPointer, remainingBytes, "0x%" PRIxPTR " ", reinterpret_cast<uintptr_t>(ptr));
if (bytes < 0 || static_cast<unsigned long>(bytes) >= remainingBytes) {
break;
}
bufferPointer += bytes;
remainingBytes -= bytes;
}
*(bufferPointer - 1) = ')'; // Replace last space.
*bufferPointer = '\0';
}
#if !defined(MACHSIZE)
#error "Define MACHSIZE to 32 or 64"
#endif
#if MACHSIZE == 32
typedef struct mach_header mach_header_target;
typedef struct segment_command segment_command_target;
typedef struct section section_target;
static const uint32_t MH_MAGIC_TARGET = MH_MAGIC;
static const uint32_t LC_SEGMENT_TARGET = LC_SEGMENT;
#elif MACHSIZE == 64
typedef struct mach_header_64 mach_header_target;
typedef struct segment_command_64 segment_command_target;
typedef struct section_64 section_target;
static const uint32_t MH_MAGIC_TARGET = MH_MAGIC_64;
static const uint32_t LC_SEGMENT_TARGET = LC_SEGMENT_64;
#else
#error "Impossible MACHSIZE"
#endif
static mach_header_target* findCoreFoundationMachHeader() {
Dl_info info;
if (dladdr(reinterpret_cast<void*>(&CFRunLoopRun), &info) == 0) return nullptr;
return reinterpret_cast<mach_header_target*>(info.dli_fbase);
}
template<int n>
bool bufferEqualsString(const char (&buffer)[n], const char* str) {
return strncmp(buffer, str, n) == 0;
}
static char* findExceptionBacktraceSection(unsigned long *size) {
mach_header_target* header = findCoreFoundationMachHeader();
if (header == nullptr) return nullptr;
if (header->magic != MH_MAGIC_TARGET) return nullptr;
uintptr_t textVmaddr = 0;
load_command* loadCommand = reinterpret_cast<load_command*>(header + 1);
for (uint32_t loadCommandIndex = 0; loadCommandIndex < header->ncmds; ++loadCommandIndex) {
if (loadCommand->cmd == LC_SEGMENT_TARGET) {
segment_command_target* segmentCommand = reinterpret_cast<segment_command_target*>(loadCommand);
if (bufferEqualsString(segmentCommand->segname, "__TEXT")) {
textVmaddr = segmentCommand->vmaddr;
}
if (bufferEqualsString(segmentCommand->segname, "__DATA")) {
section_target* sections = reinterpret_cast<section_target*>(segmentCommand + 1);
for (uint32_t sectionIndex = 0; sectionIndex < segmentCommand->nsects; ++sectionIndex) {
section_target* section = &sections[sectionIndex];
if (bufferEqualsString(section->sectname, "__cf_except_bt") && bufferEqualsString(section->segname, "__DATA")) {
*size = section->size;
return reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(header) + section->addr - textVmaddr);
}
}
}
}
loadCommand = reinterpret_cast<load_command*>(reinterpret_cast<uintptr_t>(loadCommand) + loadCommand->cmdsize);
}
return nullptr;
}
void ReportBacktraceToIosCrashLog(KRef throwable) {
unsigned long bufferSize = 0;
char* buffer = findExceptionBacktraceSection(&bufferSize);
if (buffer == nullptr) return;
// Note: access to this buffer is protected by a lock, but it is not easily accessible.
// Instead assume that typically this buffer is accessed only during termination, and
// rely on caller guaranteeing this code to be executed only before system termination handlers.
writeStackTraceToBuffer(throwable, buffer, bufferSize);
}
#endif // KONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG
@@ -0,0 +1,13 @@
#ifndef RUNTIME_OBJCEXCEPTIONS_H
#define RUNTIME_OBJCEXCEPTIONS_H
#if KONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG
#include "Common.h"
#include "Types.h"
void ReportBacktraceToIosCrashLog(KRef throwable);
#endif // KONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG
#endif // RUNTIME_OBJCEXCEPTIONS_H
@@ -0,0 +1,44 @@
#ifndef RUNTIME_OBJCEXPORT_H
#define RUNTIME_OBJCEXPORT_H
#if KONAN_OBJC_INTEROP
#import <objc/runtime.h>
#import <Foundation/NSString.h>
#import "Types.h"
#import "Memory.h"
extern "C" id objc_retain(id self);
extern "C" id objc_retainBlock(id self);
extern "C" void objc_release(id self);
inline static id GetAssociatedObject(ObjHeader* obj) {
return (id)obj->GetAssociatedObject();
}
// Note: this function shall not be used on shared objects.
inline static void SetAssociatedObject(ObjHeader* obj, id value) {
obj->SetAssociatedObject((void*)value);
}
inline static id AtomicCompareAndSwapAssociatedObject(ObjHeader* obj, id expectedValue, id newValue) {
id* location = reinterpret_cast<id*>(obj->GetAssociatedObjectLocation());
return __sync_val_compare_and_swap(location, expectedValue, newValue);
}
inline static OBJ_GETTER(AllocInstanceWithAssociatedObject, const TypeInfo* typeInfo, id associatedObject) {
ObjHeader* result = AllocInstance(typeInfo, OBJ_RESULT);
SetAssociatedObject(result, associatedObject);
return result;
}
extern "C" id Kotlin_ObjCExport_refToObjC(ObjHeader* obj);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj);
extern "C" id Kotlin_Interop_CreateNSStringFromKString(KRef str);
extern "C" OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str);
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCEXPORT_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,269 @@
/*
* Copyright 2010-2019 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.
*/
#import "Memory.h"
#import "Types.h"
#if KONAN_OBJC_INTEROP
#import <objc/runtime.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSSet.h>
#import "Exceptions.h"
#import "ObjCExport.h"
#import "ObjCExportCollections.h"
extern "C" {
// Imports from ObjCExportUtils.kt:
OBJ_GETTER0(Kotlin_NSEnumeratorAsKIterator_create);
void Kotlin_NSEnumeratorAsKIterator_done(KRef thiz);
void Kotlin_NSEnumeratorAsKIterator_setNext(KRef thiz, KRef value);
void Kotlin_ObjCExport_ThrowCollectionTooLarge();
void Kotlin_ObjCExport_ThrowCollectionConcurrentModification();
}
static inline KInt objCSizeToKotlinOrThrow(NSUInteger size) {
if (size > std::numeric_limits<KInt>::max()) {
Kotlin_ObjCExport_ThrowCollectionTooLarge();
}
return size;
}
// Exported to ObjCExportUtils.kt:
extern "C" KInt Kotlin_NSArrayAsKList_getSize(KRef obj) {
NSArray* array = (NSArray*) GetAssociatedObject(obj);
return objCSizeToKotlinOrThrow([array count]);
}
extern "C" OBJ_GETTER(Kotlin_NSArrayAsKList_get, KRef obj, KInt index) {
NSArray* array = (NSArray*) GetAssociatedObject(obj);
id element = [array objectAtIndex:index];
RETURN_RESULT_OF(refFromObjCOrNSNull, element);
}
extern "C" void Kotlin_NSMutableArrayAsKMutableList_add(KRef thiz, KInt index, KRef element) {
NSMutableArray* mutableArray = (NSMutableArray*) GetAssociatedObject(thiz);
[mutableArray insertObject:refToObjCOrNSNull(element) atIndex:index];
}
extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_removeAt, KRef thiz, KInt index) {
NSMutableArray* mutableArray = (NSMutableArray*) GetAssociatedObject(thiz);
KRef res = refFromObjCOrNSNull([mutableArray objectAtIndex:index], OBJ_RESULT);
[mutableArray removeObjectAtIndex:index];
return res;
}
extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_set, KRef thiz, KInt index, KRef element) {
NSMutableArray* mutableArray = (NSMutableArray*) GetAssociatedObject(thiz);
KRef res = refFromObjCOrNSNull([mutableArray objectAtIndex:index], OBJ_RESULT);
[mutableArray replaceObjectAtIndex:index withObject:refToObjCOrNSNull(element)];
return res;
}
extern "C" void Kotlin_NSEnumeratorAsKIterator_computeNext(KRef thiz) {
NSEnumerator* enumerator = (NSEnumerator*) GetAssociatedObject(thiz);
id next = [enumerator nextObject];
if (next == nullptr) {
Kotlin_NSEnumeratorAsKIterator_done(thiz);
} else {
ObjHolder holder;
Kotlin_NSEnumeratorAsKIterator_setNext(thiz, refFromObjCOrNSNull(next, holder.slot()));
}
}
extern "C" KInt Kotlin_NSSetAsKSet_getSize(KRef thiz) {
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
return objCSizeToKotlinOrThrow(set.count);
}
extern "C" KBoolean Kotlin_NSSetAsKSet_contains(KRef thiz, KRef element) {
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
return [set containsObject:refToObjCOrNSNull(element)];
}
extern "C" OBJ_GETTER(Kotlin_NSSetAsKSet_getElement, KRef thiz, KRef element) {
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
id res = [set member:refToObjCOrNSNull(element)];
RETURN_RESULT_OF(refFromObjCOrNSNull, res);
}
static inline OBJ_GETTER(CreateKIteratorFromNSEnumerator, NSEnumerator* enumerator) {
RETURN_RESULT_OF(invokeAndAssociate, Kotlin_NSEnumeratorAsKIterator_create, objc_retain(enumerator));
}
extern "C" OBJ_GETTER(Kotlin_NSSetAsKSet_iterator, KRef thiz) {
NSSet* set = (NSSet*) GetAssociatedObject(thiz);
RETURN_RESULT_OF(CreateKIteratorFromNSEnumerator, [set objectEnumerator]);
}
extern "C" KInt Kotlin_NSDictionaryAsKMap_getSize(KRef thiz) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
return objCSizeToKotlinOrThrow(dict.count);
}
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsKey(KRef thiz, KRef key) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
return [dict objectForKey:refToObjCOrNSNull(key)] != nullptr;
}
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsValue(KRef thiz, KRef value) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
id objCValue = refToObjCOrNSNull(value);
for (id key in dict) {
if ([[dict objectForKey:key] isEqual:objCValue]) {
return true;
}
}
return false;
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_get, KRef thiz, KRef key) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
id value = [dict objectForKey:refToObjCOrNSNull(key)];
RETURN_RESULT_OF(refFromObjCOrNSNull, value);
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_getOrThrowConcurrentModification, KRef thiz, KRef key) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
id value = [dict objectForKey:refToObjCOrNSNull(key)];
if (value == nullptr) {
Kotlin_ObjCExport_ThrowCollectionConcurrentModification();
}
RETURN_RESULT_OF(refFromObjCOrNSNull, value);
}
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsEntry(KRef thiz, KRef key, KRef value) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
return [refToObjCOrNSNull(value) isEqual:[dict objectForKey:refToObjCOrNSNull(key)]];
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_keyIterator, KRef thiz) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
RETURN_RESULT_OF(CreateKIteratorFromNSEnumerator, [dict keyEnumerator]);
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_valueIterator, KRef thiz) {
NSDictionary* dict = (NSDictionary*) GetAssociatedObject(thiz);
RETURN_RESULT_OF(CreateKIteratorFromNSEnumerator, [dict objectEnumerator]);
}
#else // KONAN_OBJC_INTEROP
extern "C" KInt Kotlin_NSArrayAsKList_getSize(KRef obj) {
RuntimeAssert(false, "Objective-C interop is disabled");
return -1;
}
extern "C" OBJ_GETTER(Kotlin_NSArrayAsKList_get, KRef obj, KInt index) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" void Kotlin_NSMutableArrayAsKMutableList_add(KRef thiz, KInt index, KRef element) {
RuntimeAssert(false, "Objective-C interop is disabled");
}
extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_removeAt, KRef thiz, KInt index) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" OBJ_GETTER(Kotlin_NSMutableArrayAsKMutableList_set, KRef thiz, KInt index, KRef element) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" void Kotlin_NSEnumeratorAsKIterator_computeNext(KRef thiz) {
RuntimeAssert(false, "Objective-C interop is disabled");
}
extern "C" KInt Kotlin_NSSetAsKSet_getSize(KRef thiz) {
RuntimeAssert(false, "Objective-C interop is disabled");
return -1;
}
extern "C" KBoolean Kotlin_NSSetAsKSet_contains(KRef thiz, KRef element) {
RuntimeAssert(false, "Objective-C interop is disabled");
return false;
}
extern "C" OBJ_GETTER(Kotlin_NSSetAsKSet_getElement, KRef thiz, KRef element) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" OBJ_GETTER(Kotlin_NSSetAsKSet_iterator, KRef thiz) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" KInt Kotlin_NSDictionaryAsKMap_getSize(KRef thiz) {
RuntimeAssert(false, "Objective-C interop is disabled");
return -1;
}
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsKey(KRef thiz, KRef key) {
RuntimeAssert(false, "Objective-C interop is disabled");
return false;
}
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsValue(KRef thiz, KRef value) {
RuntimeAssert(false, "Objective-C interop is disabled");
return false;
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_get, KRef thiz, KRef key) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_getOrThrowConcurrentModification, KRef thiz, KRef key) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" KBoolean Kotlin_NSDictionaryAsKMap_containsEntry(KRef thiz, KRef key, KRef value) {
RuntimeAssert(false, "Objective-C interop is disabled");
return false;
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_keyIterator, KRef thiz) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
extern "C" OBJ_GETTER(Kotlin_NSDictionaryAsKMap_valueIterator, KRef thiz) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
#endif // KONAN_OBJC_INTEROP
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2019 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_OBJCEXPORTCOLLECTIONS_H
#define RUNTIME_OBJCEXPORTCOLLECTIONS_H
#if KONAN_OBJC_INTEROP
#import <objc/runtime.h>
#import <Foundation/NSNull.h>
#import "Memory.h"
#import "ObjCExport.h"
#import "Runtime.h"
// Objective-C collections can't store `nil`, and the common convention is to use `NSNull.null` instead.
// Follow the convention when converting Kotlin `null`:
static inline id refToObjCOrNSNull(KRef obj) {
if (obj == nullptr) {
return NSNull.null;
} else {
return Kotlin_ObjCExport_refToObjC(obj);
}
}
static inline OBJ_GETTER(refFromObjCOrNSNull, id obj) {
if (obj == NSNull.null) {
RETURN_OBJ(nullptr);
} else {
RETURN_RESULT_OF(Kotlin_ObjCExport_refFromObjC, obj);
}
}
static inline OBJ_GETTER(invokeAndAssociate, KRef (*func)(KRef* result), id obj) {
Kotlin_initRuntimeIfNeeded();
KRef kotlinObj = func(OBJ_RESULT);
SetAssociatedObject(kotlinObj, obj);
return kotlinObj;
}
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCEXPORTCOLLECTIONS_H
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#if KONAN_OBJC_INTEROP
#import <pthread.h>
#import <Foundation/NSException.h>
#import <Foundation/NSObject.h>
#import "ObjCExport.h"
#import "ObjCExportErrors.h"
typedef void (^Completion)(id _Nullable, NSError* _Nullable);
extern "C" void Kotlin_ObjCExport_runCompletionSuccess(KRef completionHolder, KRef result) {
Completion completion = (Completion)GetAssociatedObject(completionHolder);
completion(Kotlin_ObjCExport_refToObjC(result), nullptr);
}
extern "C" void Kotlin_ObjCExport_runCompletionFailure(
KRef completionHolder,
KRef exception,
const TypeInfo** exceptionTypes
) {
id error = Kotlin_ObjCExport_ExceptionAsNSError(exception, exceptionTypes);
Completion completion = (Completion)GetAssociatedObject(completionHolder);
completion(nullptr, error);
}
extern "C" OBJ_GETTER(Kotlin_ObjCExport_createContinuationArgumentImpl,
KRef completionHolder, const TypeInfo** exceptionTypes);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_createContinuationArgument, id completion, const TypeInfo** exceptionTypes) {
if (pthread_main_np() != 1) {
[NSException raise:NSGenericException
format:@"Calling Kotlin suspend functions from Swift/Objective-C is currently supported only on main thread"];
}
ObjHolder slot;
KRef completionHolder = AllocInstanceWithAssociatedObject(theForeignObjCObjectTypeInfo,
objc_retainBlock(completion), slot.slot());
RETURN_RESULT_OF(Kotlin_ObjCExport_createContinuationArgumentImpl, completionHolder, exceptionTypes);
}
extern "C" void Kotlin_ObjCExport_resumeContinuationSuccess(KRef continuation, KRef result);
extern "C" void Kotlin_ObjCExport_resumeContinuationFailure(KRef continuation, KRef exception);
extern "C" void Kotlin_ObjCExport_resumeContinuation(KRef continuation, id result, id error) {
ObjHolder holder;
if (error != nullptr) {
if (result != nullptr) {
[NSException raise:NSGenericException
format:@"Kotlin completion handler is called with both result (%@) and error (%@) specified",
result, error];
}
KRef exception = Kotlin_ObjCExport_NSErrorAsException(error, holder.slot());
Kotlin_ObjCExport_resumeContinuationFailure(continuation, exception);
} else {
KRef kotlinResult = Kotlin_ObjCExport_refFromObjC(result, holder.slot());
Kotlin_ObjCExport_resumeContinuationSuccess(continuation, kotlinResult);
}
}
#endif
@@ -0,0 +1,9 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#import "Types.h"
extern "C" id Kotlin_ObjCExport_ExceptionAsNSError(KRef exception, const TypeInfo** types);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsException, id error);
@@ -0,0 +1,137 @@
/*
* Copyright 2010-2018 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.
*/
#if KONAN_OBJC_INTEROP
#import <Foundation/NSDictionary.h>
#import <Foundation/NSError.h>
#import <Foundation/NSString.h>
#import "Exceptions.h"
#import "ObjCExport.h"
#import "Porting.h"
#import "Runtime.h"
#import "Utils.h"
#import "ObjCExportErrors.h"
extern "C" OBJ_GETTER(Kotlin_Throwable_getMessage, KRef throwable);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_getWrappedError, KRef throwable);
static void printlnMessage(const char* message) {
konan::consolePrintf("%s\n", message);
}
extern "C" RUNTIME_NORETURN void Kotlin_ObjCExport_trapOnUndeclaredException(KRef exception) {
printlnMessage("Function doesn't have or inherit @Throws annotation and thus exception isn't propagated "
"from Kotlin to Objective-C/Swift as NSError.\n"
"It is considered unexpected and unhandled instead. Program will be terminated.");
TerminateWithUnhandledException(exception);
}
static char kotlinExceptionOriginChar;
static bool isExceptionOfType(KRef exception, const TypeInfo** types) {
if (types) for (int i = 0; types[i] != nullptr; ++i) {
// TODO: use fast instance check when possible.
if (IsInstance(exception, types[i])) return true;
}
return false;
}
extern "C" id Kotlin_ObjCExport_ExceptionAsNSError(KRef exception, const TypeInfo** types) {
ObjHolder errorHolder;
KRef error = Kotlin_ObjCExport_getWrappedError(exception, errorHolder.slot());
if (error != nullptr) {
// Thrown originally by Swift/Objective-C.
// Not actually a Kotlin exception, so don't check if it matches [types].
return Kotlin_ObjCExport_refToObjC(error);
}
if (!isExceptionOfType(exception, types)) {
printlnMessage("Exception doesn't match @Throws-specified class list and thus isn't propagated "
"from Kotlin to Objective-C/Swift as NSError.\n"
"It is considered unexpected and unhandled instead. Program will be terminated.");
TerminateWithUnhandledException(exception);
}
NSMutableDictionary<NSErrorUserInfoKey, id>* userInfo = [[NSMutableDictionary new] autorelease];
userInfo[@"KotlinException"] = Kotlin_ObjCExport_refToObjC(exception);
userInfo[@"KotlinExceptionOrigin"] = @(&kotlinExceptionOriginChar); // Support for different Kotlin runtimes loaded.
ObjHolder messageHolder;
KRef message = Kotlin_Throwable_getMessage(exception, messageHolder.slot());
NSString* description = Kotlin_Interop_CreateNSStringFromKString(message);
if (description != nullptr) {
userInfo[NSLocalizedDescriptionKey] = description;
}
return [NSError errorWithDomain:@"KotlinException" code:0 userInfo:userInfo];
}
extern "C" void Kotlin_ObjCExport_RethrowExceptionAsNSError(KRef exception, id* outError, const TypeInfo** types) {
id error = Kotlin_ObjCExport_ExceptionAsNSError(exception, types); // Also traps on unexpected exception.
if (outError != nullptr) *outError = error;
}
extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsExceptionImpl, KRef message, KRef error);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_NSErrorAsException, id error) {
NSString* description;
NSError* e = (NSError*) error;
if (e != nullptr) {
auto userInfo = e.userInfo;
if (userInfo != nullptr) {
id kotlinException = userInfo[@"KotlinException"];
id kotlinExceptionOrigin = userInfo[@"KotlinExceptionOrigin"];
if (kotlinException != nullptr &&
kotlinExceptionOrigin != nullptr && [kotlinExceptionOrigin isEqual:@(&kotlinExceptionOriginChar)]
) {
RETURN_RESULT_OF(Kotlin_ObjCExport_refFromObjC, kotlinException);
}
}
description = e.localizedDescription;
} else {
description = nullptr;
}
ObjHolder messageHolder, errorHolder;
KRef message = Kotlin_Interop_CreateKStringFromNSString(description, messageHolder.slot());
KRef kotlinError = Kotlin_ObjCExport_refFromObjC(error, errorHolder.slot()); // TODO: a simple opaque wrapper would be enough.
RETURN_RESULT_OF(Kotlin_ObjCExport_NSErrorAsExceptionImpl, message, kotlinError);
}
extern "C" void Kotlin_ObjCExport_RethrowNSErrorAsException(id error) {
ObjHolder holder;
KRef exception = Kotlin_ObjCExport_NSErrorAsException(error, holder.slot());
ThrowException(exception);
}
@interface NSError (NSErrorKotlinException)
@end;
@implementation NSError (NSErrorKotlinException)
-(id)kotlinException {
auto userInfo = self.userInfo;
return userInfo == nullptr ? nullptr : userInfo[@"KotlinException"];
}
@end;
#endif
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2020 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.
*/
#import "Memory.h"
#import "Types.h"
#ifdef __cplusplus
extern "C" {
#endif
OBJ_GETTER(Kotlin_ObjCExport_ExceptionDetails, KRef thiz, KRef exceptionHolder);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2020 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.
*/
#import "Memory.h"
#import "ObjCExportExceptionDetails.h"
#import "ObjCExport.h"
#if KONAN_OBJC_INTEROP
#import <Foundation/NSException.h>
//! TODO: Use not_null signature.
OBJ_GETTER(Kotlin_ObjCExport_ExceptionDetails, KRef /*thiz*/, KRef exceptionHolder) {
if (NSException* exception = (NSException*)Kotlin_ObjCExport_refToObjC(exceptionHolder)) {
RuntimeAssert([exception isKindOfClass:[NSException class]], "Illegal type: NSException expected");
NSString* ret = [NSString stringWithFormat: @"%@:: %@", exception.name, exception.reason];
RETURN_RESULT_OF(Kotlin_Interop_CreateKStringFromNSString, ret);
}
RETURN_OBJ(nullptr);
}
#else // KONAN_OBJC_INTEROP
OBJ_GETTER(Kotlin_ObjCExport_ExceptionDetails, KRef /*thiz*/, KRef /*exceptionHolder*/) {
RETURN_OBJ(nullptr);
}
#endif
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_OBJCEXPORTINIT_H
#define RUNTIME_OBJCEXPORTINIT_H
#if KONAN_OBJC_INTEROP
extern "C" void Kotlin_ObjCExport_initialize(void);
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCEXPORTINIT_H
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_OBJCEXPORTPRIVATE_H
#define RUNTIME_OBJCEXPORTPRIVATE_H
#if KONAN_OBJC_INTEROP
#import <objc/runtime.h>
#import "Types.h"
#import "Memory.h"
#import "ObjCExport.h"
@interface KotlinBase : NSObject <NSCopying>
+(instancetype)createWrapper:(ObjHeader*)obj;
@end;
extern "C" void Kotlin_ObjCExport_initializeClass(Class clazz);
extern "C" const TypeInfo* Kotlin_ObjCExport_getAssociatedTypeInfo(Class clazz);
extern "C" OBJ_GETTER(Kotlin_ObjCExport_convertUnmappedObjCObject, id obj);
extern "C" SEL Kotlin_ObjCExport_toKotlinSelector;
extern "C" SEL Kotlin_ObjCExport_releaseAsAssociatedObjectSelector;
const TypeInfo* Kotlin_ObjCExport_createTypeInfoWithKotlinFieldsFrom(Class clazz, const TypeInfo* fieldsInfo);
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCEXPORTPRIVATE_H
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_OBJCINTEROP_H
#define RUNTIME_OBJCINTEROP_H
#if KONAN_OBJC_INTEROP
const char* Kotlin_ObjCInterop_getUniquePrefix();
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCINTEROP_H
@@ -0,0 +1,374 @@
/*
* 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.
*/
#if KONAN_OBJC_INTEROP
#import <Foundation/NSException.h>
#import <objc/objc-exception.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <objc/message.h>
#include <cstdio>
#include <cstdint>
#include "Memory.h"
#include "MemorySharedRefs.hpp"
#include "Natives.h"
#include "ObjCInterop.h"
#include "ObjCExportPrivate.h"
#include "Types.h"
#include "Utils.h"
// Replaced in ObjCExportCodeGenerator.
__attribute__((weak)) const char* Kotlin_ObjCInterop_uniquePrefix = nullptr;
const char* Kotlin_ObjCInterop_getUniquePrefix() {
auto result = Kotlin_ObjCInterop_uniquePrefix;
RuntimeCheck(result != nullptr, "unique prefix is not initialized");
return result;
}
extern "C" id objc_msgSendSuper2(struct objc_super *super, SEL op, ...);
struct KotlinClassData {
const TypeInfo* typeInfo;
int32_t bodyOffset;
};
static inline struct KotlinClassData* GetKotlinClassData(Class clazz) {
void* ivars = object_getIndexedIvars(reinterpret_cast<id>(clazz));
return static_cast<struct KotlinClassData*>(ivars);
}
namespace {
BackRefFromAssociatedObject* getBackRef(id obj, KotlinClassData* classData) {
void* body = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + classData->bodyOffset);
return reinterpret_cast<BackRefFromAssociatedObject*>(body);
}
BackRefFromAssociatedObject* getBackRef(id obj) {
// TODO: suboptimal; consider specializing methods for each class.
auto* classData = GetKotlinClassData(object_getClass(obj));
return getBackRef(obj, classData);
}
OBJ_GETTER(toKotlinImp, id self, SEL _cmd) {
RETURN_OBJ(getBackRef(self)->ref<ErrorPolicy::kTerminate>());
}
id allocWithZoneImp(Class self, SEL _cmd, void* zone) {
// [super allocWithZone:zone]
struct objc_super s = {(id)self, object_getClass((id)self)};
auto messenger = reinterpret_cast<id (*) (struct objc_super*, SEL _cmd, void* zone)>(objc_msgSendSuper2);
id result = messenger(&s, _cmd, zone);
auto* classData = GetKotlinClassData(self); // TODO: suboptimal; consider specializing.
auto* typeInfo = classData->typeInfo;
ObjHolder holder;
auto kotlinObj = AllocInstanceWithAssociatedObject(typeInfo, result, holder.slot());
getBackRef(result, classData)->initAndAddRef(kotlinObj);
return result;
}
id retainImp(id self, SEL _cmd) {
getBackRef(self)->addRef<ErrorPolicy::kTerminate>();
return self;
}
BOOL _tryRetainImp(id self, SEL _cmd) {
// TODO: [tryAddRef] currently works only on the owner thread for non-shared objects;
// this is a regression for instances of Kotlin subclasses of Obj-C classes:
// loading a reference to such an object from Obj-C weak reference now fails on "wrong" thread
// unless the object is frozen.
try {
return getBackRef(self)->tryAddRef<ErrorPolicy::kThrow>();
} catch (ExceptionObjHolder& e) {
// TODO: check for IncorrectDereferenceException and possible weak property access
// Cannot use SourceInfo here, because CoreSymbolication framework (CSSymbolOwnerGetSymbolWithAddress)
// fails at recursive retain lock. Similarly, cannot use objc exception here, because its unhandled
// exception handler might fail at recursive retain lock too.
// TODO: Refactor to be more explicit. Instead of relying on an unhandled exception termination
// (and effectively setting a global to alter its behavior), just call an appropriate termination
// function by hand.
DisallowSourceInfo();
std::terminate();
}
}
void releaseImp(id self, SEL _cmd) {
getBackRef(self)->releaseRef();
}
void releaseAsAssociatedObjectImp(id self, SEL _cmd) {
// This function is called by the GC. It made a decision to reclaim Kotlin object, and runs
// deallocation hooks at the moment, including deallocation of the "associated object" ([self])
// using the [super release] call below.
// The deallocation involves running [self dealloc] which can contain arbitrary code.
// In particular, this code can retain and release [self]. Obj-C and Swift runtimes handle this
// gracefully (unless the object gets accessed after the deallocation of course), but Kotlin doesn't.
// For example, this happens in https://youtrack.jetbrains.com/issue/KT-41811, provoked by
// UIViewController.dealloc (which retains-releases self._view._viewDelegate == self) and UIView.dealloc.
// Generally retaining and releasing Kotlin object that is being deallocated would lead to
// use-after-dispose and double-dispose problems (with unpredictable consequences) or to an assertion failure.
// To workaround this, detach the back ref from the Kotlin object:
getBackRef(self)->detach();
// So retain/release/etc. on [self] won't affect the Kotlin object, and an attempt to get
// the reference to it (e.g. when calling Kotlin method on [self]) would crash.
// The latter is generally ok, because by the time superclass dealloc gets launched, subclass state
// should already be deinitialized, and Kotlin methods operate on the subclass.
// [super release]
Class clazz = object_getClass(self);
struct objc_super s = {self, clazz};
auto messenger = reinterpret_cast<void (*) (struct objc_super*, SEL _cmd)>(objc_msgSendSuper2);
messenger(&s, @selector(release));
}
}
extern "C" {
Class Kotlin_Interop_getObjCClass(const char* name);
static inline void SetKotlinTypeInfo(Class clazz, const TypeInfo* typeInfo) {
GetKotlinClassData(clazz)->typeInfo = typeInfo;
}
const TypeInfo* GetObjCKotlinTypeInfo(ObjHeader* obj) RUNTIME_NOTHROW;
RUNTIME_NOTHROW const TypeInfo* GetObjCKotlinTypeInfo(ObjHeader* obj) {
void* objcPtr = obj->GetAssociatedObject();
RuntimeAssert(objcPtr != nullptr, "");
Class clazz = object_getClass(reinterpret_cast<id>(objcPtr));
return GetKotlinClassData(clazz)->typeInfo;
}
static void AddNSObjectOverride(bool isClassMethod, Class clazz, SEL selector, void* imp) {
Class nsObjectClass = Kotlin_Interop_getObjCClass("NSObject");
Method nsObjectMethod = class_getInstanceMethod(
isClassMethod ? object_getClass((id)nsObjectClass) : nsObjectClass, selector);
RuntimeCheck(nsObjectMethod != nullptr, "NSObject method not found");
const char* nsObjectMethodTypeEncoding = method_getTypeEncoding(nsObjectMethod);
RuntimeCheck(nsObjectMethodTypeEncoding != nullptr, "NSObject method has no encoding provided");
// TODO: something of the above can be cached.
BOOL added = class_addMethod(
isClassMethod ? object_getClass((id)clazz) : clazz, selector, (IMP)imp, nsObjectMethodTypeEncoding);
RuntimeCheck(added, "Unable to add method to Objective-C class");
}
struct ObjCMethodDescription {
void* (*imp)(void*, void*, ...);
const char* selector;
const char* encoding;
};
struct KotlinObjCClassInfo {
const char* name;
int exported;
const char* superclassName;
const char** protocolNames;
const struct ObjCMethodDescription* instanceMethods;
int32_t instanceMethodsNum;
const struct ObjCMethodDescription* classMethods;
int32_t classMethodsNum;
int32_t* bodyOffset;
const TypeInfo* typeInfo;
const TypeInfo* metaTypeInfo;
void** createdClass;
};
static void AddMethods(Class clazz, const struct ObjCMethodDescription* methods, int32_t methodsNum) {
for (int32_t i = 0; i < methodsNum; ++i) {
const struct ObjCMethodDescription* method = &methods[i];
BOOL added = class_addMethod(clazz, sel_registerName(method->selector), (IMP)method->imp, method->encoding);
RuntimeAssert(added == YES, "Unable to add method to Objective-C class");
}
}
static SimpleMutex classCreationMutex;
static int anonymousClassNextId = 0;
static Class allocateClass(const KotlinObjCClassInfo* info) {
Class superclass = Kotlin_Interop_getObjCClass(info->superclassName);
size_t extraBytes = sizeof(struct KotlinClassData);
if (info->exported) {
RuntimeCheck(info->name != nullptr, "exported Objective-C class must have a name");
Class result = objc_allocateClassPair(superclass, info->name, extraBytes);
if (result != nullptr) return result;
// Similar to how Objective-C runtime handles this:
fprintf(stderr, "Class %s has multiple implementations. Which one will be used is undefined.\n", info->name);
}
KStdString className = Kotlin_ObjCInterop_getUniquePrefix();
if (info->name != nullptr) {
className += info->name;
} else {
className += "_kobjc";
}
int classId = anonymousClassNextId++;
className += std::to_string(classId);
Class result = objc_allocateClassPair(superclass, className.c_str(), extraBytes);
RuntimeCheck(result != nullptr, "Failed to allocate Objective-C class");
return result;
}
void* CreateKotlinObjCClass(const KotlinObjCClassInfo* info) {
LockGuard<SimpleMutex> lockGuard(classCreationMutex);
void* createdClass = *info->createdClass;
if (createdClass != nullptr) {
return createdClass;
}
Class newClass = allocateClass(info);
RuntimeAssert(newClass != nullptr, "Failed to allocate Objective-C class");
Class newMetaclass = object_getClass(reinterpret_cast<id>(newClass));
for (size_t i = 0;; ++i) {
const char* protocolName = info->protocolNames[i];
if (protocolName == nullptr) break;
Protocol* proto = objc_getProtocol(protocolName);
if (proto != nullptr) {
BOOL added = class_addProtocol(newClass, proto);
RuntimeAssert(added == YES, "Unable to add protocol to Objective-C class");
added = class_addProtocol(newMetaclass, proto);
RuntimeAssert(added == YES, "Unable to add protocol to Objective-C metaclass");
}
}
AddNSObjectOverride(false, newClass, Kotlin_ObjCExport_toKotlinSelector, (void*)&toKotlinImp);
AddNSObjectOverride(true, newClass, @selector(allocWithZone:), (void*)&allocWithZoneImp);
AddNSObjectOverride(false, newClass, @selector(retain), (void*)&retainImp);
AddNSObjectOverride(false, newClass, @selector(_tryRetain), (void*)&_tryRetainImp);
AddNSObjectOverride(false, newClass, @selector(release), (void*)&releaseImp);
AddNSObjectOverride(false, newClass, Kotlin_ObjCExport_releaseAsAssociatedObjectSelector,
(void*)&releaseAsAssociatedObjectImp);
AddMethods(newClass, info->instanceMethods, info->instanceMethodsNum);
AddMethods(newMetaclass, info->classMethods, info->classMethodsNum);
SetKotlinTypeInfo(newClass, Kotlin_ObjCExport_createTypeInfoWithKotlinFieldsFrom(newClass, info->typeInfo));
int bodySize = sizeof(BackRefFromAssociatedObject);
char bodyTypeEncoding[16];
snprintf(bodyTypeEncoding, sizeof(bodyTypeEncoding), "[%dc]", bodySize);
BOOL added = class_addIvar(newClass, "kotlinBody", bodySize, /* log2(align) = */ 3, bodyTypeEncoding);
RuntimeAssert(added == YES, "Unable to add ivar to Objective-C class");
objc_registerClassPair(newClass);
Ivar body = class_getInstanceVariable(newClass, "kotlinBody");
RuntimeAssert(body != nullptr, "Unable to get ivar added to Objective-C class");
int32_t offset = (int32_t)ivar_getOffset(body);
GetKotlinClassData(newClass)->bodyOffset = offset;
*info->bodyOffset = offset;
*info->createdClass = newClass;
return newClass;
}
void* objc_autoreleasePoolPush();
void objc_autoreleasePoolPop(void* ptr);
id objc_allocWithZone(Class clazz);
id objc_retain(id ptr);
void objc_release(id ptr);
void* Kotlin_objc_autoreleasePoolPush() {
return objc_autoreleasePoolPush();
}
void Kotlin_objc_autoreleasePoolPop(void* ptr) {
objc_autoreleasePoolPop(ptr);
}
id Kotlin_objc_allocWithZone(Class clazz) {
return objc_allocWithZone(clazz);
}
id Kotlin_objc_retain(id ptr) {
return objc_retain(ptr);
}
void Kotlin_objc_release(id ptr) {
objc_release(ptr);
}
Class Kotlin_objc_lookUpClass(const char* name) {
return objc_lookUpClass(name);
}
} // extern "C"
#else // KONAN_OBJC_INTEROP
#include "KAssert.h"
extern "C" {
void* Kotlin_objc_autoreleasePoolPush() {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
void Kotlin_objc_autoreleasePoolPop(void* ptr) {
RuntimeAssert(false, "Objective-C interop is disabled");
}
void* Kotlin_objc_allocWithZone(void* clazz) {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
void* Kotlin_objc_retain(void* ptr) {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
void Kotlin_objc_release(void* ptr) {
RuntimeAssert(false, "Objective-C interop is disabled");
}
void* Kotlin_objc_lookUpClass(const char* name) {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
} // extern "C"
#endif // KONAN_OBJC_INTEROP
@@ -0,0 +1,174 @@
/*
* 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.
*/
#include "Natives.h"
#if KONAN_OBJC_INTEROP
#import <objc/runtime.h>
#import <CoreFoundation/CFString.h>
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
#import "Memory.h"
#import "ObjCInteropUtilsPrivate.h"
namespace {
Class nsStringClass = nullptr;
Class getNSStringClass() {
Class result = nsStringClass;
if (result == nullptr) {
// Lookup dynamically to avoid direct reference to Foundation:
result = objc_getClass("NSString");
RuntimeAssert(result != nullptr, "NSString class not found");
nsStringClass = result;
}
return result;
}
// Note: using @"foo" string literals leads to linkage dependency on frameworks.
NSString* cStringToNS(const char* str) {
return [getNSStringClass() stringWithCString:str encoding:NSUTF8StringEncoding];
}
}
extern "C" {
id Kotlin_ObjCExport_CreateNSStringFromKString(ObjHeader* str);
id Kotlin_Interop_CreateNSStringFromKString(ObjHeader* str) {
// Note: this function is just a bit specialized [Kotlin_Interop_refToObjC].
if (str == nullptr) {
return nullptr;
}
if (void* associatedObject = str->GetAssociatedObject()) {
return (id)associatedObject;
}
return Kotlin_ObjCExport_CreateNSStringFromKString(str);
}
OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str) {
if (str == nullptr) {
RETURN_OBJ(nullptr);
}
CFStringRef immutableCopyOrSameStr = CFStringCreateCopy(nullptr, (CFStringRef)str);
auto length = CFStringGetLength(immutableCopyOrSameStr);
CFRange range = {0, length};
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, length, OBJ_RESULT)->array();
KChar* rawResult = CharArrayAddressOfElementAt(result, 0);
CFStringGetCharacters(immutableCopyOrSameStr, range, rawResult);
result->obj()->SetAssociatedObject((void*)immutableCopyOrSameStr);
RETURN_OBJ(result->obj());
}
// Note: this body is used for init methods with signatures differing from this;
// it is correct on arm64 and x86_64, because the body uses only the first two arguments which are fixed,
// and returns pointers.
id MissingInitImp(id self, SEL _cmd) {
const char* className = object_getClassName(self);
[self release]; // Since init methods receive ownership on the receiver.
// Lookup dynamically to avoid direct reference to Foundation:
Class nsExceptionClass = objc_getClass("NSException");
RuntimeAssert(nsExceptionClass != nullptr, "NSException class not found");
[nsExceptionClass raise:cStringToNS("Initializer is not implemented")
format:cStringToNS("%s is not implemented in %s"),
sel_getName(_cmd), className];
return nullptr;
}
// Initialized in [ObjCInteropUtilsClasses.mm].
id (*Kotlin_Interop_createKotlinObjectHolder_ptr)(KRef any) = nullptr;
KRef (*Kotlin_Interop_unwrapKotlinObjectHolder_ptr)(id holder) = nullptr;
id Kotlin_Interop_createKotlinObjectHolder(KRef any) {
return Kotlin_Interop_createKotlinObjectHolder_ptr(any);
}
KRef Kotlin_Interop_unwrapKotlinObjectHolder(id holder) {
return Kotlin_Interop_unwrapKotlinObjectHolder_ptr(holder);
}
KBoolean Kotlin_Interop_DoesObjectConformToProtocol(id obj, void* prot, KBoolean isMeta) {
BOOL objectIsClass = class_isMetaClass(object_getClass(obj));
if ((isMeta && !objectIsClass) || (!isMeta && objectIsClass)) return false;
// TODO: handle root classes properly.
return [((id<NSObject>)obj) conformsToProtocol:(Protocol*)prot];
}
KBoolean Kotlin_Interop_IsObjectKindOfClass(id obj, void* cls) {
return [((id<NSObject>)obj) isKindOfClass:(Class)cls];
}
OBJ_GETTER((*Konan_ObjCInterop_getWeakReference_ptr), KRef ref) = nullptr;
void (*Konan_ObjCInterop_initWeakReference_ptr)(KRef ref, id objcPtr) = nullptr;
OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
RETURN_RESULT_OF(Konan_ObjCInterop_getWeakReference_ptr, ref);
}
void Konan_ObjCInterop_initWeakReference(KRef ref, id objcPtr) {
Konan_ObjCInterop_initWeakReference_ptr(ref, objcPtr);
}
} // extern "C"
#else // KONAN_OBJC_INTEROP
extern "C" {
void* Kotlin_Interop_CreateNSStringFromKString(const ArrayHeader* str) {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, void* str) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
void* Kotlin_Interop_createKotlinObjectHolder(KRef any) {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
KRef Kotlin_Interop_unwrapKotlinObjectHolder(void* holder) {
RuntimeAssert(false, "Objective-C interop is disabled");
return nullptr;
}
OBJ_GETTER(Konan_ObjCInterop_getWeakReference, KRef ref) {
RuntimeAssert(false, "Objective-C interop is disabled");
RETURN_OBJ(nullptr);
}
void Konan_ObjCInterop_initWeakReference(KRef ref, void* objcPtr) {
RuntimeAssert(false, "Objective-C interop is disabled");
}
} // extern "C"
#endif // KONAN_OBJC_INTEROP
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_OBJCINTEROPUTILSPRIVATE_H
#define RUNTIME_OBJCINTEROPUTILSPRIVATE_H
#if KONAN_OBJC_INTEROP
#import <objc/runtime.h>
#import "Types.h"
#import "Memory.h"
extern "C" id (*Kotlin_Interop_createKotlinObjectHolder_ptr)(KRef any);
extern "C" KRef (*Kotlin_Interop_unwrapKotlinObjectHolder_ptr)(id holder);
extern "C" OBJ_GETTER((*Konan_ObjCInterop_getWeakReference_ptr), KRef ref);
extern "C" void (*Konan_ObjCInterop_initWeakReference_ptr)(KRef ref, id objcPtr);
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCINTEROPUTILSPRIVATE_H
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_OBJCMMAPI_H
#define RUNTIME_OBJCMMAPI_H
#include "Common.h"
#if KONAN_OBJC_INTEROP
extern "C" ALWAYS_INLINE void Kotlin_ObjCExport_releaseAssociatedObject(void* associatedObject);
#endif // KONAN_OBJC_INTEROP
#endif // RUNTIME_OBJCMMAPI_H
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2018 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.
*/
#include <math.h>
#include <limits.h>
#include "DoubleConversions.h"
#include "Natives.h"
#include "Common.h"
extern "C" {
//--- Float -------------------------------------------------------------------//
KInt Kotlin_Float_toInt(KFloat a) {
if (isnan(a)) return 0;
if (a >= (KFloat) INT32_MAX) return INT32_MAX;
if (a <= (KFloat) INT32_MIN) return INT32_MIN;
return a;
}
KLong Kotlin_Float_toLong(KFloat a) {
if (isnan(a)) return 0;
if (a >= (KFloat) INT64_MAX) return INT64_MAX;
if (a <= (KFloat) INT64_MIN) return INT64_MIN;
return a;
}
KByte Kotlin_Float_toByte(KFloat a) { return (KByte) Kotlin_Float_toInt(a); }
KShort Kotlin_Float_toShort(KFloat a) { return (KShort) Kotlin_Float_toInt(a); }
ALWAYS_INLINE KBoolean Kotlin_Float_isNaN(KFloat a) { return isnan(a); }
ALWAYS_INLINE KBoolean Kotlin_Float_isInfinite(KFloat a) { return isinf(a); }
ALWAYS_INLINE KBoolean Kotlin_Float_isFinite(KFloat a) { return isfinite(a); }
//--- Double ------------------------------------------------------------------//
KInt Kotlin_Double_toInt(KDouble a) {
if (isnan(a)) return 0;
if (a >= (KDouble) INT32_MAX) return INT32_MAX;
if (a <= (KDouble) INT32_MIN) return INT32_MIN;
return a;
}
KLong Kotlin_Double_toLong(KDouble a) {
if (isnan(a)) return 0;
if (a >= (KDouble) INT64_MAX) return INT64_MAX;
if (a <= (KDouble) INT64_MIN) return INT64_MIN;
return a;
}
ALWAYS_INLINE KBoolean Kotlin_Double_isNaN(KDouble a) { return isnan(a); }
ALWAYS_INLINE KBoolean Kotlin_Double_isInfinite(KDouble a) { return isinf(a); }
ALWAYS_INLINE KBoolean Kotlin_Double_isFinite(KDouble a) { return isfinite(a); }
//--- Bit operations ---------------------------------------------------------//
ALWAYS_INLINE KInt Kotlin_Int_countOneBits(KInt value) { return __builtin_popcount(value); }
ALWAYS_INLINE KInt Kotlin_Long_countOneBits(KLong value) { return __builtin_popcountll(value); }
ALWAYS_INLINE KInt Kotlin_Int_countTrailingZeroBits(KInt value) { return __builtin_ctz(value); }
ALWAYS_INLINE KInt Kotlin_Long_countTrailingZeroBits(KLong value) { return __builtin_ctzll(value); }
ALWAYS_INLINE KInt Kotlin_Int_countLeadingZeroBits(KInt value) { return __builtin_clz(value); }
ALWAYS_INLINE KInt Kotlin_Long_countLeadingZeroBits(KLong value) { return __builtin_clzll(value); }
} // extern "C"
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_POINTER_BITS_H
#define RUNTIME_POINTER_BITS_H
#include <cstdint>
#include "Common.h"
template <typename T>
ALWAYS_INLINE T* setPointerBits(T* ptr, unsigned bits) {
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) | bits);
}
template <typename T>
ALWAYS_INLINE T* clearPointerBits(T* ptr, unsigned bits) {
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) & ~static_cast<uintptr_t>(bits));
}
template <typename T>
ALWAYS_INLINE unsigned getPointerBits(T* ptr, unsigned bits) {
return reinterpret_cast<uintptr_t>(ptr) & static_cast<uintptr_t>(bits);
}
template <typename T>
ALWAYS_INLINE bool hasPointerBits(T* ptr, unsigned bits) {
return getPointerBits(ptr, bits) != 0;
}
#endif // RUNTIME_POINTER_BITS_H
@@ -0,0 +1,545 @@
/*
* 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.
*/
#ifdef KONAN_ANDROID
#include <android/log.h>
#endif
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if !KONAN_NO_THREADS
#include <pthread.h>
#endif
#include <unistd.h>
#if KONAN_WINDOWS
#include <windows.h>
#endif
#include <chrono>
#include "Common.h"
#include "Porting.h"
#include "KAssert.h"
#if KONAN_WASM || KONAN_ZEPHYR
extern "C" RUNTIME_NORETURN void Konan_abort(const char*);
extern "C" RUNTIME_NORETURN void Konan_exit(int32_t status);
#endif
#ifdef KONAN_ZEPHYR
// In Zephyr's Newlib strnlen(3) is not included from string.h by default.
extern "C" size_t strnlen(const char* buffer, size_t maxSize);
#endif
namespace konan {
// Console operations.
void consoleInit() {
#if KONAN_WINDOWS
// Note that this code enforces UTF-8 console output, so we may want to rethink
// how we perform console IO, if it turns out, that UTF-16 is better output format.
::SetConsoleCP(CP_UTF8);
::SetConsoleOutputCP(CP_UTF8);
// FIXME: should set original CP back during the deinit of the program.
// Otherwise, this codepage remains in the console.
#endif
}
void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes) {
#ifdef KONAN_ANDROID
// TODO: use sizeBytes!
__android_log_print(ANDROID_LOG_INFO, "Konan_main", "%s", utf8);
#else
::write(STDOUT_FILENO, utf8, sizeBytes);
#endif
}
void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes) {
#ifdef KONAN_ANDROID
// TODO: use sizeBytes!
__android_log_print(ANDROID_LOG_ERROR, "Konan_main", "%s", utf8);
#else
::write(STDERR_FILENO, utf8, sizeBytes);
#endif
}
#if KONAN_WINDOWS
int getLastErrorMessage(char* message, uint32_t size) {
auto errCode = ::GetLastError();
if (errCode) {
auto flags = FORMAT_MESSAGE_FROM_SYSTEM;
auto errMsgBufSize = size / 4;
wchar_t errMsgBuffer[errMsgBufSize];
::FormatMessageW(flags, NULL, errCode, 0, errMsgBuffer, errMsgBufSize, NULL);
::WideCharToMultiByte(CP_UTF8, 0, errMsgBuffer, -1, message, size, NULL, NULL);
}
return errCode;
}
#endif
int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) {
#ifdef KONAN_ZEPHYR
return 0;
#elif KONAN_WINDOWS
auto length = 0;
void *stdInHandle = ::GetStdHandle(STD_INPUT_HANDLE);
if (::GetFileType(stdInHandle) == FILE_TYPE_CHAR) {
unsigned long bufferRead;
// In UTF-16 there are surrogate pairs that a 2 * 16-bit long (4 bytes).
auto bufferLength = maxSizeBytes / 4 - 1;
wchar_t buffer[bufferLength];
if (::ReadConsoleW(stdInHandle, buffer, bufferLength, &bufferRead, NULL)) {
length = ::WideCharToMultiByte(CP_UTF8, 0, buffer, bufferRead, (char*) utf8,
maxSizeBytes - 1, NULL, NULL);
if (!length && KonanNeedDebugInfo) {
char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("UTF-16 to UTF-8 conversion error %d: %s", errCode, msg);
}
((char*) utf8)[length] = 0;
} else if (KonanNeedDebugInfo) {
char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("Console read failure: %d %s", errCode, msg);
}
} else {
length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1);
}
#else
auto length = ::read(STDIN_FILENO, utf8, maxSizeBytes - 1);
#endif
if (length <= 0) return -1;
char* start = reinterpret_cast<char*>(utf8);
char* current = start + length - 1;
bool isTrimming = true;
while (current >= start && isTrimming) {
switch (*current) {
case '\n':
case '\r':
*current = 0;
length--;
break;
default:
isTrimming = false;
}
current--;
}
return length;
}
#if KONAN_INTERNAL_SNPRINTF
extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list);
#define vsnprintf_impl rpl_vsnprintf
#else
#define vsnprintf_impl ::vsnprintf
#endif
void consolePrintf(const char* format, ...) {
char buffer[1024];
va_list args;
va_start(args, format);
int rv = vsnprintf_impl(buffer, sizeof(buffer), format, args);
if (rv < 0) return; // TODO: this may be too much exotic, but should i try to print itoa(error) and terminate?
if (static_cast<size_t>(rv) >= sizeof(buffer)) rv = sizeof(buffer) - 1; // TODO: Consider realloc or report truncating.
va_end(args);
consoleWriteUtf8(buffer, rv);
}
// TODO: Avoid code duplication.
void consoleErrorf(const char* format, ...) {
char buffer[1024];
va_list args;
va_start(args, format);
int rv = vsnprintf_impl(buffer, sizeof(buffer), format, args);
if (rv < 0) return; // TODO: this may be too much exotic, but should i try to print itoa(error) and terminate?
if (static_cast<size_t>(rv) >= sizeof(buffer)) rv = sizeof(buffer) - 1; // TODO: Consider realloc or report truncating.
va_end(args);
consoleErrorUtf8(buffer, rv);
}
void consoleFlush() {
::fflush(stdout);
::fflush(stderr);
}
// Thread execution.
#if !KONAN_NO_THREADS
pthread_key_t terminationKey;
pthread_once_t terminationKeyOnceControl = PTHREAD_ONCE_INIT;
typedef void (*destructor_t)(void*);
struct DestructorRecord {
struct DestructorRecord* next;
destructor_t destructor;
void* destructorParameter;
};
static void onThreadExitCallback(void* value) {
DestructorRecord* record = reinterpret_cast<DestructorRecord*>(value);
while (record != nullptr) {
record->destructor(record->destructorParameter);
auto next = record->next;
free(record);
record = next;
}
pthread_setspecific(terminationKey, nullptr);
}
#if KONAN_LINUX
static pthread_key_t dummyKey;
#endif
static void onThreadExitInit() {
#if KONAN_LINUX
// Due to glibc bug we have to create first key as dummy, to avoid
// conflicts with potentially uninitialized dlfcn error key.
// https://code.woboq.org/userspace/glibc/dlfcn/dlerror.c.html#237
// As one may see, glibc checks value of the key even if it was not inited (and == 0),
// and so data associated with our legit key (== 0 as being the first one) is used.
// Other libc are not affected, as usually == 0 pthread key is impossible.
pthread_key_create(&dummyKey, nullptr);
#endif
pthread_key_create(&terminationKey, onThreadExitCallback);
}
#endif // !KONAN_NO_THREADS
void onThreadExit(void (*destructor)(void*), void* destructorParameter) {
#if KONAN_NO_THREADS
#if KONAN_WASM || KONAN_ZEPHYR
// No way to do that.
#else
#error "How to do onThreadExit()?"
#endif
#else // !KONAN_NO_THREADS
// We cannot use pthread_cleanup_push() as it is lexical scope bound.
pthread_once(&terminationKeyOnceControl, onThreadExitInit);
DestructorRecord* destructorRecord = (DestructorRecord*)calloc(1, sizeof(DestructorRecord));
destructorRecord->destructor = destructor;
destructorRecord->destructorParameter = destructorParameter;
destructorRecord->next =
reinterpret_cast<DestructorRecord*>(pthread_getspecific(terminationKey));
pthread_setspecific(terminationKey, destructorRecord);
#endif // !KONAN_NO_THREADS
}
// Process execution.
void abort(void) {
::abort();
}
#if KONAN_WASM || KONAN_ZEPHYR
void exit(int32_t status) {
Konan_exit(status);
}
#else
void exit(int32_t status) {
::exit(status);
}
#endif
// String/byte operations.
// memcpy/memmove are not here intentionally, as frequently implemented/optimized
// by C compiler.
void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLen) {
#if KONAN_NO_MEMMEM
for (size_t i = 0; i + littleLen <= bigLen; ++i) {
void* pos = ((char*)big) + i;
if (::memcmp(little, pos, littleLen) == 0) return pos;
}
return nullptr;
#else
return ::memmem(big, bigLen, little, littleLen);
#endif
}
// The sprintf family.
int snprintf(char* buffer, size_t size, const char* format, ...) {
va_list args;
va_start(args, format);
int rv = vsnprintf_impl(buffer, size, format, args);
va_end(args);
return rv;
}
size_t strnlen(const char* buffer, size_t maxSize) {
return ::strnlen(buffer, maxSize);
}
// Memory operations.
#if KONAN_INTERNAL_DLMALLOC
extern "C" void* dlcalloc(size_t, size_t);
extern "C" void dlfree(void*);
#define calloc_impl dlcalloc
#define free_impl dlfree
#define calloc_aligned_impl(count, size, alignment) dlcalloc(count, size)
#else
extern "C" void* konan_calloc_impl(size_t, size_t);
extern "C" void konan_free_impl(void*);
extern "C" void* konan_calloc_aligned_impl(size_t count, size_t size, size_t alignment);
#define calloc_impl konan_calloc_impl
#define free_impl konan_free_impl
#define calloc_aligned_impl konan_calloc_aligned_impl
#endif
void* calloc(size_t count, size_t size) {
return calloc_impl(count, size);
}
void* calloc_aligned(size_t count, size_t size, size_t alignment) {
return calloc_aligned_impl(count, size, alignment);
}
void free(void* pointer) {
free_impl(pointer);
}
#if KONAN_INTERNAL_NOW
#ifdef KONAN_ZEPHYR
void Konan_date_now(uint64_t* arg) {
// TODO: so how will we support time for embedded?
*arg = 0LL;
}
#else
extern "C" void Konan_date_now(uint64_t*);
#endif
uint64_t getTimeMillis() {
uint64_t now;
Konan_date_now(&now);
return now;
}
uint64_t getTimeMicros() {
return getTimeMillis() * 1000ULL;
}
uint64_t getTimeNanos() {
return getTimeMillis() * 1000000ULL;
}
#else
// Time operations.
using namespace std::chrono;
// Get steady clock as a source of time
using steady_time_clock = std::conditional<high_resolution_clock::is_steady, high_resolution_clock, steady_clock>::type;
uint64_t getTimeMillis() {
return duration_cast<milliseconds>(steady_time_clock::now().time_since_epoch()).count();
}
uint64_t getTimeNanos() {
return duration_cast<nanoseconds>(steady_time_clock::now().time_since_epoch()).count();
}
uint64_t getTimeMicros() {
return duration_cast<microseconds>(steady_time_clock::now().time_since_epoch()).count();
}
#endif
#if KONAN_INTERNAL_DLMALLOC
// This function is being called when memory allocator needs more RAM.
#if KONAN_WASM
namespace {
constexpr uint32_t MFAIL = ~(uint32_t)0;
constexpr uint32_t WASM_PAGESIZE_EXPONENT = 16;
constexpr uint32_t WASM_PAGESIZE = 1u << WASM_PAGESIZE_EXPONENT;
constexpr uint32_t WASM_PAGEMASK = WASM_PAGESIZE-1;
uint32_t pageAlign(int32_t value) {
return (value + WASM_PAGEMASK) & ~ (WASM_PAGEMASK);
}
uint32_t inBytes(uint32_t pageCount) {
return pageCount << WASM_PAGESIZE_EXPONENT;
}
uint32_t inPages(uint32_t value) {
return value >> WASM_PAGESIZE_EXPONENT;
}
extern "C" void Konan_notify_memory_grow();
uint32_t memorySize() {
return __builtin_wasm_memory_size(0);
}
int32_t growMemory(uint32_t delta) {
int32_t oldLength = __builtin_wasm_memory_grow(0, delta);
Konan_notify_memory_grow();
return oldLength;
}
}
void* moreCore(int32_t delta) {
uint32_t top = inBytes(memorySize());
if (delta > 0) {
if (growMemory(inPages(pageAlign(delta))) == 0) {
return (void *) MFAIL;
}
} else if (delta < 0) {
return (void *) MFAIL;
}
return (void *) top;
}
// dlmalloc() wants to know the page size.
long getpagesize() {
return WASM_PAGESIZE;
}
#else
void* moreCore(int size) {
return sbrk(size);
}
long getpagesize() {
return sysconf(_SC_PAGESIZE);
}
#endif
#endif
} // namespace konan
extern "C" {
// TODO: get rid of these.
#if (KONAN_WASM || KONAN_ZEPHYR)
void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv(void) {
Konan_abort("TODO: throw_length_error not implemented.");
}
void _ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv(void) {
Konan_abort("TODO: throw_length_error not implemented.");
}
void _ZNKSt3__121__basic_string_commonILb1EE20__throw_length_errorEv(void) {
Konan_abort("TODO: throw_length_error not implemented.");
}
void _ZNKSt3__221__basic_string_commonILb1EE20__throw_length_errorEv(void) {
Konan_abort("TODO: throw_length_error not implemented.");
}
int _ZNSt3__212__next_primeEj(unsigned long n) {
static unsigned long primes[] = {
11UL,
101UL,
1009UL,
10007UL,
100003UL,
1000003UL,
10000019UL,
100000007UL,
1000000007UL
};
size_t table_length = sizeof(primes)/sizeof(unsigned long);
if (n > primes[table_length - 1]) konan::abort();
unsigned long prime = primes[0];
for (unsigned long i=0; i< table_length; i++) {
prime = primes[i];
if (prime >= n) break;
}
return prime;
}
int _ZNSt3__212__next_primeEm(int n) {
return _ZNSt3__212__next_primeEj(n);
}
int _ZNSt3__112__next_primeEj(unsigned long n) {
return _ZNSt3__212__next_primeEj(n);
}
void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function) {
char buf[1024];
konan::snprintf(buf, sizeof(buf), "%s:%d in %s: runtime assert: %s\n", file, line, function, assertion);
Konan_abort(buf);
}
int* __errno_location() {
static int theErrno = 0;
return &theErrno;
}
// Some math.h functions.
double pow(double x, double y) {
return __builtin_pow(x, y);
}
#endif
#ifdef KONAN_WASM
// Some string.h functions.
void *memcpy(void *dst, const void *src, size_t n) {
for (size_t i = 0; i != n; ++i)
*((char*)dst + i) = *((char*)src + i);
return dst;
}
void *memmove(void *dst, const void *src, size_t len) {
if (src < dst) {
for (long i = len; i != 0; --i) {
*((char*)dst + i - 1) = *((char*)src + i - 1);
}
} else {
memcpy(dst, src, len);
}
return dst;
}
int memcmp(const void *s1, const void *s2, size_t n) {
for (size_t i = 0; i != n; ++i) {
if (*((char*)s1 + i) != *((char*)s2 + i)) {
return *((char*)s1 + i) - *((char*)s2 + i);
}
}
return 0;
}
void *memset(void *b, int c, size_t len) {
for (size_t i = 0; i != len; ++i) {
*((char*)b + i) = c;
}
return b;
}
size_t strlen(const char *s) {
for (long i = 0;; ++i) {
if (s[i] == 0) return i;
}
}
size_t strnlen(const char *s, size_t maxlen) {
for (size_t i = 0; i<=maxlen; ++i) {
if (s[i] == 0) return i;
}
return maxlen;
}
#endif
#ifdef KONAN_ZEPHYR
RUNTIME_USED void Konan_abort(const char*) {
while(1) {}
}
#endif // KONAN_ZEPHYR
} // extern "C"
@@ -0,0 +1,100 @@
/*
* 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_PORTING_H
#define RUNTIME_PORTING_H
#include <stdint.h>
#include <stddef.h>
#include "Common.h"
namespace konan {
// Console operations.
void consoleInit();
void consolePrintf(const char* format, ...);
void consoleErrorf(const char* format, ...);
void consoleWriteUtf8(const void* utf8, uint32_t sizeBytes);
void consoleErrorUtf8(const void* utf8, uint32_t sizeBytes);
// Negative return value denotes that read wasn't successful.
int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes);
void consoleFlush();
// Process control.
RUNTIME_NORETURN void abort(void);
RUNTIME_NORETURN void exit(int32_t status);
// Thread control.
void onThreadExit(void (*destructor)(void*), void* destructorParameter);
// String/byte operations.
// memcpy/memmove/memcmp are not here intentionally, as frequently implemented/optimized
// by C compiler.
void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLen);
int snprintf(char* buffer, size_t size, const char* format, ...);
size_t strnlen(const char* buffer, size_t maxSize);
// These functions should be marked with RUNTIME_USED attribute for wasm target
// because clang replaces these operations with intrinsics that will be
// replaced back to library calls only on codegen step. And there is no stdlib
// for wasm target for now :(
// Otherwise `opt` will see no usages of these definitions and will remove them.
extern "C" {
#ifdef KONAN_WASM
RUNTIME_USED
double pow(double x, double y);
RUNTIME_USED
void *memcpy(void *dst, const void *src, size_t n);
RUNTIME_USED
void *memmove(void *dst, const void *src, size_t len);
RUNTIME_USED
int memcmp(const void *s1, const void *s2, size_t n);
RUNTIME_USED
void *memset(void *b, int c, size_t len);
#endif
}
// Memory operations.
void* calloc(size_t count, size_t size);
void* calloc_aligned(size_t count, size_t size, size_t alignment);
void free(void* ptr);
// Time operations.
uint64_t getTimeMillis();
uint64_t getTimeMicros();
uint64_t getTimeNanos();
#if KONAN_NO_EXCEPTIONS
#define TRY_CATCH(tryAction, actionWithoutExceptions, catchAction) actionWithoutExceptions;
#else
#define TRY_CATCH(tryAction, actionWithoutExceptions, catchAction) \
do { \
try { tryAction; } \
catch(...) { catchAction; } \
} while(0)
#endif
} // namespace konan
#endif // RUNTIME_PORTING_H
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "PthreadUtils.h"
#include <pthread.h>
#include <sys/time.h>
namespace {
constexpr int64_t kNanosecondsInASecond = 1000000000LL;
} // namespace
int WaitOnCondVar(
pthread_cond_t* cond,
pthread_mutex_t* mutex,
uint64_t timeoutNanoseconds,
uint64_t* microsecondsPassed) {
struct timeval tvBefore;
// TODO: Error reporting?
gettimeofday(&tvBefore, nullptr);
struct timespec ts;
const uint64_t nanoseconds = tvBefore.tv_usec * 1000LL + timeoutNanoseconds;
ts.tv_sec = tvBefore.tv_sec + nanoseconds / kNanosecondsInASecond;
ts.tv_nsec = nanoseconds % kNanosecondsInASecond;
auto result = pthread_cond_timedwait(cond, mutex, &ts);
if (microsecondsPassed) {
struct timeval tvAfter;
// TODO: Error reporting?
gettimeofday(&tvAfter, nullptr);
*microsecondsPassed = (tvAfter.tv_sec - tvBefore.tv_sec) * 1000000LL +
tvAfter.tv_usec - tvBefore.tv_usec;
}
return result;
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_PTHREAD_UTILS_H
#define RUNTIME_PTHREAD_UTILS_H
#include <cstdint>
#include <pthread.h>
// Releases mutex and waits on cond for timeoutNanoseconds.
// Returns ETIMEDOUT if timeoutNanoseconds has passed.
int WaitOnCondVar(
pthread_cond_t* cond,
pthread_mutex_t* mutex,
uint64_t timeoutNanoseconds,
uint64_t* microsecondsPassed = nullptr);
#endif // RUNTIME_PTHREAD_UTILS_H
@@ -0,0 +1,622 @@
#include <cstring>
#include "Types.h"
#include "KString.h"
#include "Natives.h"
namespace {
/* Contains canonical classes (see http://www.unicode.org/Public/4.0-Update/UnicodeData-4.0.0.txt). */
constexpr KInt canonicalClassesKeys[] = {
768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790,
791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813,
814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836,
837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860,
861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 1155, 1156, 1157, 1158,
1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443,
1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462,
1463, 1464, 1465, 1467, 1468, 1469, 1471, 1473, 1474, 1476, 1477, 1479, 1552, 1553, 1554, 1555, 1556, 1557, 1611,
1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630,
1648, 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1759, 1760, 1761, 1762, 1763, 1764, 1767, 1768, 1770, 1771, 1772,
1773, 1809, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1856,
1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 2364, 2381, 2385, 2386, 2387, 2388, 2492, 2509, 2620,
2637, 2748, 2765, 2876, 2893, 3021, 3149, 3157, 3158, 3260, 3277, 3405, 3530, 3640, 3641, 3642, 3656, 3657, 3658,
3659, 3768, 3769, 3784, 3785, 3786, 3787, 3864, 3865, 3893, 3895, 3897, 3953, 3954, 3956, 3962, 3963, 3964, 3965,
3968, 3970, 3971, 3972, 3974, 3975, 4038, 4151, 4153, 4959, 5908, 5940, 6098, 6109, 6313, 6457, 6458, 6459, 6679,
6680, 7616, 7617, 7618, 7619, 8400, 8401, 8402, 8403, 8404, 8405, 8406, 8407, 8408, 8409, 8410, 8411, 8412, 8417,
8421, 8422, 8423, 8424, 8425, 8426, 8427, 12330, 12331, 12332, 12333, 12334, 12335, 12441, 12442, 43014, 64286, 65056,
65057, 65058, 65059, 68109, 68111, 68152, 68153, 68154, 68159, 119141, 119142, 119143, 119144, 119145, 119149, 119150,
119151, 119152, 119153, 119154, 119163, 119164, 119165, 119166, 119167, 119168, 119169, 119170, 119173, 119174,
119175, 119176, 119177, 119178, 119179, 119210, 119211, 119212, 119213, 119362, 119363, 119364,
};
constexpr KInt canonicalClassesValues[] = {
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 232, 220,
220, 220, 220, 232, 216, 220, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220,
220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220, 220, 220, 220, 230, 230, 230, 230, 230, 230, 230, 230, 240, 230,
220, 220, 220, 230, 230, 230, 220, 220, 230, 230, 230, 220, 220, 220, 220, 230, 232, 220, 220, 230, 233, 234, 234,
233, 234, 234, 233, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 220, 230,
230, 230, 230, 220, 230, 230, 230, 222, 220, 230, 230, 230, 230, 230, 230, 220, 220, 220, 220, 220, 220, 230, 230,
220, 230, 230, 222, 228, 230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 230, 220, 18, 230, 230,
230, 230, 230, 230, 27, 28, 29, 30, 31, 32, 33, 34, 230, 230, 220, 220, 230, 230, 230, 230, 230, 220, 230, 230, 35,
230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 220, 230, 230, 230, 220, 230, 230, 220, 36, 230, 220, 230, 230,
220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230, 230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 7,
9, 230, 220, 230, 230, 7, 9, 7, 9, 7, 9, 7, 9, 9, 9, 84, 91, 7, 9, 9, 9, 103, 103, 9, 107, 107, 107, 107, 118, 118,
122, 122, 122, 122, 220, 220, 220, 220, 216, 129, 130, 132, 130, 130, 130, 130, 130, 230, 230, 9, 230, 230, 220, 7, 9,
230, 9, 9, 9, 230, 228, 222, 230, 220, 230, 220, 230, 230, 220, 230, 230, 230, 1, 1, 230, 230, 230, 230, 1, 1, 1, 230,
230, 230, 1, 1, 230, 220, 230, 1, 1, 218, 228, 232, 222, 224, 224, 8, 8, 9, 26, 230, 230, 230, 230, 220, 230, 230, 1,
220, 9, 216, 216, 1, 1, 1, 226, 216, 216, 216, 216, 216, 220, 220, 220, 220, 220, 220, 220, 220, 230, 230, 230, 230,
230, 220, 220, 230, 230, 230, 230, 230, 230, 230,
};
/* Symbols that are one symbol decompositions (see http://www.unicode.org/Public/4.0-Update/UnicodeData-4.0.0.txt). */
constexpr KInt singleDecompositions[] = {
59, 75, 96, 180, 183, 197, 697, 768, 769, 787, 901, 902, 904, 905, 906, 908, 910, 911, 912, 937, 940, 941, 942, 943,
944, 953, 972, 973, 974, 8194, 8195, 12296, 12297, 13470, 13497, 13499, 13535, 13589, 14062, 14076, 14209, 14383,
14434, 14460, 14535, 14563, 14620, 14650, 14894, 14956, 15076, 15112, 15129, 15177, 15261, 15384, 15438, 15667, 15766,
16044, 16056, 16155, 16380, 16392, 16408, 16441, 16454, 16534, 16611, 16687, 16898, 16935, 17056, 17153, 17204, 17241,
17365, 17369, 17419, 17515, 17707, 17757, 17761, 17771, 17879, 17913, 17973, 18110, 18119, 18837, 18918, 19054, 19062,
19122, 19251, 19406, 19662, 19693, 19704, 19798, 19981, 20006, 20018, 20024, 20025, 20029, 20033, 20098, 20102, 20142,
20160, 20172, 20196, 20320, 20352, 20358, 20363, 20398, 20411, 20415, 20482, 20523, 20602, 20633, 20687, 20698, 20711,
20800, 20805, 20813, 20820, 20836, 20839, 20840, 20841, 20845, 20855, 20864, 20877, 20882, 20885, 20887, 20900, 20908,
20917, 20919, 20937, 20940, 20956, 20958, 20981, 20995, 20999, 21015, 21033, 21050, 21051, 21062, 21106, 21111, 21129,
21147, 21155, 21171, 21191, 21193, 21202, 21214, 21220, 21237, 21242, 21253, 21254, 21271, 21311, 21321, 21329, 21338,
21363, 21365, 21373, 21375, 21443, 21450, 21471, 21477, 21483, 21489, 21510, 21519, 21533, 21560, 21570, 21576, 21608,
21662, 21666, 21693, 21750, 21776, 21843, 21845, 21859, 21892, 21895, 21913, 21917, 21931, 21939, 21952, 21954, 21986,
22022, 22097, 22120, 22132, 22265, 22294, 22295, 22411, 22478, 22516, 22541, 22577, 22578, 22592, 22618, 22622, 22696,
22700, 22707, 22744, 22751, 22766, 22770, 22775, 22790, 22810, 22818, 22852, 22856, 22865, 22868, 22882, 22899, 23000,
23020, 23067, 23079, 23138, 23142, 23221, 23304, 23336, 23358, 23429, 23491, 23512, 23527, 23534, 23539, 23551, 23558,
23586, 23615, 23648, 23650, 23652, 23653, 23662, 23693, 23744, 23833, 23875, 23888, 23915, 23918, 23932, 23986, 23994,
24033, 24034, 24061, 24104, 24125, 24169, 24180, 24230, 24240, 24243, 24246, 24265, 24266, 24274, 24275, 24281, 24300,
24318, 24324, 24354, 24403, 24418, 24425, 24427, 24459, 24474, 24489, 24493, 24525, 24535, 24565, 24569, 24594, 24604,
24705, 24724, 24775, 24792, 24801, 24840, 24900, 24904, 24908, 24910, 24928, 24936, 24954, 24974, 24976, 24996, 25007,
25010, 25054, 25074, 25078, 25088, 25104, 25115, 25134, 25140, 25181, 25265, 25289, 25295, 25299, 25300, 25340, 25342,
25405, 25424, 25448, 25467, 25475, 25504, 25513, 25540, 25541, 25572, 25628, 25634, 25682, 25705, 25719, 25726, 25754,
25757, 25796, 25935, 25942, 25964, 25976, 26009, 26053, 26082, 26083, 26131, 26185, 26228, 26248, 26257, 26268, 26292,
26310, 26356, 26360, 26368, 26391, 26395, 26401, 26446, 26451, 26454, 26462, 26491, 26501, 26519, 26611, 26618, 26647,
26655, 26706, 26753, 26757, 26766, 26792, 26900, 26946, 27043, 27114, 27138, 27155, 27304, 27347, 27355, 27396, 27425,
27476, 27506, 27511, 27513, 27551, 27566, 27578, 27579, 27726, 27751, 27784, 27839, 27852, 27853, 27877, 27926, 27931,
27934, 27956, 27966, 27969, 28009, 28010, 28023, 28024, 28037, 28107, 28122, 28138, 28153, 28186, 28207, 28270, 28316,
28346, 28359, 28363, 28369, 28379, 28431, 28450, 28451, 28526, 28614, 28651, 28670, 28699, 28702, 28729, 28746, 28784,
28791, 28797, 28825, 28845, 28872, 28889, 28997, 29001, 29038, 29084, 29134, 29136, 29200, 29211, 29224, 29227, 29237,
29264, 29282, 29312, 29333, 29359, 29376, 29436, 29482, 29557, 29562, 29575, 29579, 29605, 29618, 29662, 29702, 29705,
29730, 29767, 29788, 29801, 29809, 29829, 29833, 29848, 29898, 29958, 29988, 30011, 30014, 30041, 30053, 30064, 30178,
30224, 30237, 30239, 30274, 30313, 30410, 30427, 30439, 30452, 30465, 30494, 30495, 30528, 30538, 30603, 30631, 30798,
30827, 30860, 30865, 30922, 30924, 30971, 31018, 31036, 31038, 31048, 31049, 31056, 31062, 31069, 31070, 31077, 31103,
31117, 31118, 31119, 31150, 31178, 31211, 31260, 31296, 31306, 31311, 31361, 31409, 31435, 31470, 31520, 31680, 31686,
31689, 31806, 31840, 31867, 31890, 31934, 31954, 31958, 31971, 31975, 31976, 32000, 32016, 32034, 32047, 32091, 32099,
32160, 32190, 32199, 32244, 32258, 32265, 32311, 32321, 32325, 32574, 32626, 32633, 32634, 32645, 32661, 32666, 32701,
32762, 32769, 32773, 32838, 32864, 32879, 32880, 32894, 32907, 32941, 32946, 33027, 33086, 33240, 33256, 33261, 33281,
33284, 33391, 33401, 33419, 33425, 33437, 33457, 33459, 33469, 33509, 33510, 33565, 33571, 33590, 33618, 33619, 33635,
33709, 33725, 33737, 33738, 33740, 33756, 33767, 33775, 33777, 33853, 33865, 33879, 34030, 34033, 34035, 34044, 34070,
34148, 34253, 34298, 34310, 34322, 34349, 34367, 34384, 34396, 34407, 34409, 34440, 34473, 34530, 34574, 34600, 34667,
34681, 34694, 34746, 34785, 34817, 34847, 34892, 34912, 34915, 35010, 35023, 35031, 35038, 35041, 35064, 35066, 35088,
35137, 35172, 35206, 35211, 35222, 35488, 35498, 35519, 35531, 35538, 35542, 35565, 35576, 35582, 35585, 35641, 35672,
35712, 35722, 35912, 35925, 36011, 36033, 36034, 36040, 36051, 36104, 36123, 36215, 36284, 36299, 36335, 36336, 36554,
36564, 36646, 36650, 36664, 36667, 36706, 36766, 36784, 36790, 36899, 36920, 36978, 36988, 37007, 37012, 37070, 37105,
37117, 37137, 37147, 37226, 37273, 37300, 37324, 37327, 37329, 37428, 37432, 37494, 37500, 37591, 37592, 37636, 37706,
37881, 37909, 38283, 38317, 38327, 38446, 38475, 38477, 38517, 38520, 38524, 38534, 38563, 38584, 38595, 38626, 38627,
38646, 38647, 38691, 38706, 38728, 38742, 38875, 38880, 38911, 38923, 38936, 38953, 38971, 39006, 39138, 39151, 39164,
39208, 39209, 39335, 39362, 39409, 39422, 39530, 39698, 39791, 40000, 40023, 40189, 40295, 40372, 40442, 40478, 40575,
40599, 40607, 40635, 40654, 40697, 40702, 40709, 40719, 40726, 40763, 40771, 40845, 40846, 40860, 131362, 132380,
132389, 132427, 132666, 133124, 133342, 133676, 133987, 136420, 136872, 136938, 137672, 138008, 138507, 138724,
138726, 139651, 139679, 140081, 141012, 141380, 141386, 142092, 142321, 143370, 144056, 144223, 144275, 144284,
144323, 144341, 144493, 145059, 145575, 146061, 146170, 146620, 146718, 147153, 147294, 147342, 148067, 148395,
149000, 149301, 149524, 150582, 150674, 151457, 151480, 151620, 151794, 151795, 151833, 151859, 152137, 152605,
153126, 153242, 153285, 153980, 154279, 154539, 154752, 154832, 155526, 156122, 156200, 156231, 156377, 156478,
156890, 156963, 157096, 157607, 157621, 158524, 158774, 158933, 159083, 159532, 159665, 159954, 160714, 161383,
161966, 162150, 162984, 163539, 163631, 165330, 165357, 165678, 166906, 167287, 168261, 168415, 168474, 168970,
169110, 169398, 170800, 172238, 172293, 172558, 172689, 172946, 173568
};
constexpr KInt decompositionKeys[] = {
192, 193, 194, 195, 196, 197, 199, 200, 201, 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 217, 218,
219, 220, 221, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234, 235, 236, 237, 238, 239, 241, 242, 243, 244, 245,
246, 249, 250, 251, 252, 253, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,
274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 296, 297, 298,
299, 300, 301, 302, 303, 304, 308, 309, 310, 311, 313, 314, 315, 316, 317, 318, 323, 324, 325, 326, 327, 328, 332,
333, 334, 335, 336, 337, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357,
360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382,
416, 417, 431, 432, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 478, 479, 480,
481, 482, 483, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 500, 501, 504, 505, 506, 507, 508, 509, 510,
511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533,
534, 535, 536, 537, 538, 539, 542, 543, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 832,
833, 835, 836, 884, 894, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 938, 939, 940, 941, 942, 943, 944, 970,
971, 972, 973, 974, 979, 980, 1024, 1025, 1027, 1031, 1036, 1037, 1038, 1049, 1081, 1104, 1105, 1107, 1111, 1116,
1117, 1118, 1142, 1143, 1217, 1218, 1232, 1233, 1234, 1235, 1238, 1239, 1242, 1243, 1244, 1245, 1246, 1247, 1250,
1251, 1252, 1253, 1254, 1255, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1272, 1273,
1570, 1571, 1572, 1573, 1574, 1728, 1730, 1747, 2345, 2353, 2356, 2392, 2393, 2394, 2395, 2396, 2397, 2398, 2399,
2507, 2508, 2524, 2525, 2527, 2611, 2614, 2649, 2650, 2651, 2654, 2888, 2891, 2892, 2908, 2909, 2964, 3018, 3019,
3020, 3144, 3264, 3271, 3272, 3274, 3275, 3402, 3403, 3404, 3546, 3548, 3549, 3550, 3907, 3917, 3922, 3927, 3932,
3945, 3955, 3957, 3958, 3960, 3969, 3987, 3997, 4002, 4007, 4012, 4025, 4134, 7680, 7681, 7682, 7683, 7684, 7685,
7686, 7687, 7688, 7689, 7690, 7691, 7692, 7693, 7694, 7695, 7696, 7697, 7698, 7699, 7700, 7701, 7702, 7703, 7704,
7705, 7706, 7707, 7708, 7709, 7710, 7711, 7712, 7713, 7714, 7715, 7716, 7717, 7718, 7719, 7720, 7721, 7722, 7723,
7724, 7725, 7726, 7727, 7728, 7729, 7730, 7731, 7732, 7733, 7734, 7735, 7736, 7737, 7738, 7739, 7740, 7741, 7742,
7743, 7744, 7745, 7746, 7747, 7748, 7749, 7750, 7751, 7752, 7753, 7754, 7755, 7756, 7757, 7758, 7759, 7760, 7761,
7762, 7763, 7764, 7765, 7766, 7767, 7768, 7769, 7770, 7771, 7772, 7773, 7774, 7775, 7776, 7777, 7778, 7779, 7780,
7781, 7782, 7783, 7784, 7785, 7786, 7787, 7788, 7789, 7790, 7791, 7792, 7793, 7794, 7795, 7796, 7797, 7798, 7799,
7800, 7801, 7802, 7803, 7804, 7805, 7806, 7807, 7808, 7809, 7810, 7811, 7812, 7813, 7814, 7815, 7816, 7817, 7818,
7819, 7820, 7821, 7822, 7823, 7824, 7825, 7826, 7827, 7828, 7829, 7830, 7831, 7832, 7833, 7835, 7840, 7841, 7842,
7843, 7844, 7845, 7846, 7847, 7848, 7849, 7850, 7851, 7852, 7853, 7854, 7855, 7856, 7857, 7858, 7859, 7860, 7861,
7862, 7863, 7864, 7865, 7866, 7867, 7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 7876, 7877, 7878, 7879, 7880,
7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, 7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899,
7900, 7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, 7912, 7913, 7914, 7915, 7916, 7917, 7918,
7919, 7920, 7921, 7922, 7923, 7924, 7925, 7926, 7927, 7928, 7929, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943,
7944, 7945, 7946, 7947, 7948, 7949, 7950, 7951, 7952, 7953, 7954, 7955, 7956, 7957, 7960, 7961, 7962, 7963, 7964,
7965, 7968, 7969, 7970, 7971, 7972, 7973, 7974, 7975, 7976, 7977, 7978, 7979, 7980, 7981, 7982, 7983, 7984, 7985,
7986, 7987, 7988, 7989, 7990, 7991, 7992, 7993, 7994, 7995, 7996, 7997, 7998, 7999, 8000, 8001, 8002, 8003, 8004,
8005, 8008, 8009, 8010, 8011, 8012, 8013, 8016, 8017, 8018, 8019, 8020, 8021, 8022, 8023, 8025, 8027, 8029, 8031,
8032, 8033, 8034, 8035, 8036, 8037, 8038, 8039, 8040, 8041, 8042, 8043, 8044, 8045, 8046, 8047, 8048, 8049, 8050,
8051, 8052, 8053, 8054, 8055, 8056, 8057, 8058, 8059, 8060, 8061, 8064, 8065, 8066, 8067, 8068, 8069, 8070, 8071,
8072, 8073, 8074, 8075, 8076, 8077, 8078, 8079, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090,
8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 8099, 8100, 8101, 8102, 8103, 8104, 8105, 8106, 8107, 8108, 8109,
8110, 8111, 8112, 8113, 8114, 8115, 8116, 8118, 8119, 8120, 8121, 8122, 8123, 8124, 8126, 8129, 8130, 8131, 8132,
8134, 8135, 8136, 8137, 8138, 8139, 8140, 8141, 8142, 8143, 8144, 8145, 8146, 8147, 8150, 8151, 8152, 8153, 8154,
8155, 8157, 8158, 8159, 8160, 8161, 8162, 8163, 8164, 8165, 8166, 8167, 8168, 8169, 8170, 8171, 8172, 8173, 8174,
8175, 8178, 8179, 8180, 8182, 8183, 8184, 8185, 8186, 8187, 8188, 8189, 8192, 8193, 8486, 8490, 8491, 8602, 8603,
8622, 8653, 8654, 8655, 8708, 8713, 8716, 8740, 8742, 8769, 8772, 8775, 8777, 8800, 8802, 8813, 8814, 8815, 8816,
8817, 8820, 8821, 8824, 8825, 8832, 8833, 8836, 8837, 8840, 8841, 8876, 8877, 8878, 8879, 8928, 8929, 8930, 8931,
8938, 8939, 8940, 8941, 9001, 9002, 10972, 12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382,
12384, 12386, 12389, 12391, 12393, 12400, 12401, 12403, 12404, 12406, 12407, 12409, 12410, 12412, 12413, 12436, 12446,
12460, 12462, 12464, 12466, 12468, 12470, 12472, 12474, 12476, 12478, 12480, 12482, 12485, 12487, 12489, 12496, 12497,
12499, 12500, 12502, 12503, 12505, 12506, 12508, 12509, 12532, 12535, 12536, 12537, 12538, 12542, 63744, 63745, 63746,
63747, 63748, 63749, 63750, 63751, 63752, 63753, 63754, 63755, 63756, 63757, 63758, 63759, 63760, 63761, 63762, 63763,
63764, 63765, 63766, 63767, 63768, 63769, 63770, 63771, 63772, 63773, 63774, 63775, 63776, 63777, 63778, 63779, 63780,
63781, 63782, 63783, 63784, 63785, 63786, 63787, 63788, 63789, 63790, 63791, 63792, 63793, 63794, 63795, 63796, 63797,
63798, 63799, 63800, 63801, 63802, 63803, 63804, 63805, 63806, 63807, 63808, 63809, 63810, 63811, 63812, 63813, 63814,
63815, 63816, 63817, 63818, 63819, 63820, 63821, 63822, 63823, 63824, 63825, 63826, 63827, 63828, 63829, 63830, 63831,
63832, 63833, 63834, 63835, 63836, 63837, 63838, 63839, 63840, 63841, 63842, 63843, 63844, 63845, 63846, 63847, 63848,
63849, 63850, 63851, 63852, 63853, 63854, 63855, 63856, 63857, 63858, 63859, 63860, 63861, 63862, 63863, 63864, 63865,
63866, 63867, 63868, 63869, 63870, 63871, 63872, 63873, 63874, 63875, 63876, 63877, 63878, 63879, 63880, 63881, 63882,
63883, 63884, 63885, 63886, 63887, 63888, 63889, 63890, 63891, 63892, 63893, 63894, 63895, 63896, 63897, 63898, 63899,
63900, 63901, 63902, 63903, 63904, 63905, 63906, 63907, 63908, 63909, 63910, 63911, 63912, 63913, 63914, 63915, 63916,
63917, 63918, 63919, 63920, 63921, 63922, 63923, 63924, 63925, 63926, 63927, 63928, 63929, 63930, 63931, 63932, 63933,
63934, 63935, 63936, 63937, 63938, 63939, 63940, 63941, 63942, 63943, 63944, 63945, 63946, 63947, 63948, 63949, 63950,
63951, 63952, 63953, 63954, 63955, 63956, 63957, 63958, 63959, 63960, 63961, 63962, 63963, 63964, 63965, 63966, 63967,
63968, 63969, 63970, 63971, 63972, 63973, 63974, 63975, 63976, 63977, 63978, 63979, 63980, 63981, 63982, 63983, 63984,
63985, 63986, 63987, 63988, 63989, 63990, 63991, 63992, 63993, 63994, 63995, 63996, 63997, 63998, 63999, 64000, 64001,
64002, 64003, 64004, 64005, 64006, 64007, 64008, 64009, 64010, 64011, 64012, 64013, 64016, 64018, 64021, 64022, 64023,
64024, 64025, 64026, 64027, 64028, 64029, 64030, 64032, 64034, 64037, 64038, 64042, 64043, 64044, 64045, 64048, 64049,
64050, 64051, 64052, 64053, 64054, 64055, 64056, 64057, 64058, 64059, 64060, 64061, 64062, 64063, 64064, 64065, 64066,
64067, 64068, 64069, 64070, 64071, 64072, 64073, 64074, 64075, 64076, 64077, 64078, 64079, 64080, 64081, 64082, 64083,
64084, 64085, 64086, 64087, 64088, 64089, 64090, 64091, 64092, 64093, 64094, 64095, 64096, 64097, 64098, 64099, 64100,
64101, 64102, 64103, 64104, 64105, 64106, 64112, 64113, 64114, 64115, 64116, 64117, 64118, 64119, 64120, 64121, 64122,
64123, 64124, 64125, 64126, 64127, 64128, 64129, 64130, 64131, 64132, 64133, 64134, 64135, 64136, 64137, 64138, 64139,
64140, 64141, 64142, 64143, 64144, 64145, 64146, 64147, 64148, 64149, 64150, 64151, 64152, 64153, 64154, 64155, 64156,
64157, 64158, 64159, 64160, 64161, 64162, 64163, 64164, 64165, 64166, 64167, 64168, 64169, 64170, 64171, 64172, 64173,
64174, 64175, 64176, 64177, 64178, 64179, 64180, 64181, 64182, 64183, 64184, 64185, 64186, 64187, 64188, 64189, 64190,
64191, 64192, 64193, 64194, 64195, 64196, 64197, 64198, 64199, 64200, 64201, 64202, 64203, 64204, 64205, 64206, 64207,
64208, 64209, 64210, 64211, 64212, 64213, 64214, 64215, 64216, 64217, 64285, 64287, 64298, 64299, 64300, 64301, 64302,
64303, 64304, 64305, 64306, 64307, 64308, 64309, 64310, 64312, 64313, 64314, 64315, 64316, 64318, 64320, 64321, 64323,
64324, 64326, 64327, 64328, 64329, 64330, 64331, 64332, 64333, 64334, 119134, 119135, 119136, 119137, 119138, 119139,
119140, 119227, 119228, 119229, 119230, 119231, 119232, 194560, 194561, 194562, 194563, 194564, 194565, 194566,
194567, 194568, 194569, 194570, 194571, 194572, 194573, 194574, 194575, 194576, 194577, 194578, 194579, 194580,
194581, 194582, 194583, 194584, 194585, 194586, 194587, 194588, 194589, 194590, 194591, 194592, 194593, 194594,
194595, 194596, 194597, 194598, 194599, 194600, 194601, 194602, 194603, 194604, 194605, 194606, 194607, 194608,
194609, 194610, 194611, 194612, 194613, 194614, 194615, 194616, 194617, 194618, 194619, 194620, 194621, 194622,
194623, 194624, 194625, 194626, 194627, 194628, 194629, 194630, 194631, 194632, 194633, 194634, 194635, 194636,
194637, 194638, 194639, 194640, 194641, 194642, 194643, 194644, 194645, 194646, 194647, 194648, 194649, 194650,
194651, 194652, 194653, 194654, 194655, 194656, 194657, 194658, 194659, 194660, 194661, 194662, 194663, 194664,
194665, 194666, 194667, 194668, 194669, 194670, 194671, 194672, 194673, 194674, 194675, 194676, 194677, 194678,
194679, 194680, 194681, 194682, 194683, 194684, 194685, 194686, 194687, 194688, 194689, 194690, 194691, 194692,
194693, 194694, 194695, 194696, 194697, 194698, 194699, 194700, 194701, 194702, 194703, 194704, 194705, 194706,
194707, 194708, 194709, 194710, 194711, 194712, 194713, 194714, 194715, 194716, 194717, 194718, 194719, 194720,
194721, 194722, 194723, 194724, 194725, 194726, 194727, 194728, 194729, 194730, 194731, 194732, 194733, 194734,
194735, 194736, 194737, 194738, 194739, 194740, 194741, 194742, 194743, 194744, 194745, 194746, 194747, 194748,
194749, 194750, 194751, 194752, 194753, 194754, 194755, 194756, 194757, 194758, 194759, 194760, 194761, 194762,
194763, 194764, 194765, 194766, 194767, 194768, 194769, 194770, 194771, 194772, 194773, 194774, 194775, 194776,
194777, 194778, 194779, 194780, 194781, 194782, 194783, 194784, 194785, 194786, 194787, 194788, 194789, 194790,
194791, 194792, 194793, 194794, 194795, 194796, 194797, 194798, 194799, 194800, 194801, 194802, 194803, 194804,
194805, 194806, 194807, 194808, 194809, 194810, 194811, 194812, 194813, 194814, 194815, 194816, 194817, 194818,
194819, 194820, 194821, 194822, 194823, 194824, 194825, 194826, 194827, 194828, 194829, 194830, 194831, 194832,
194833, 194834, 194835, 194836, 194837, 194838, 194839, 194840, 194841, 194842, 194843, 194844, 194845, 194846,
194847, 194848, 194849, 194850, 194851, 194852, 194853, 194854, 194855, 194856, 194857, 194858, 194859, 194860,
194861, 194862, 194863, 194864, 194865, 194866, 194867, 194868, 194869, 194870, 194871, 194872, 194873, 194874,
194875, 194876, 194877, 194878, 194879, 194880, 194881, 194882, 194883, 194884, 194885, 194886, 194887, 194888,
194889, 194890, 194891, 194892, 194893, 194894, 194895, 194896, 194897, 194898, 194899, 194900, 194901, 194902,
194903, 194904, 194905, 194906, 194907, 194908, 194909, 194910, 194911, 194912, 194913, 194914, 194915, 194916,
194917, 194918, 194919, 194920, 194921, 194922, 194923, 194924, 194925, 194926, 194927, 194928, 194929, 194930,
194931, 194932, 194933, 194934, 194935, 194936, 194937, 194938, 194939, 194940, 194941, 194942, 194943, 194944,
194945, 194946, 194947, 194948, 194949, 194950, 194951, 194952, 194953, 194954, 194955, 194956, 194957, 194958,
194959, 194960, 194961, 194962, 194963, 194964, 194965, 194966, 194967, 194968, 194969, 194970, 194971, 194972,
194973, 194974, 194975, 194976, 194977, 194978, 194979, 194980, 194981, 194982, 194983, 194984, 194985, 194986,
194987, 194988, 194989, 194990, 194991, 194992, 194993, 194994, 194995, 194996, 194997, 194998, 194999, 195000,
195001, 195002, 195003, 195004, 195005, 195006, 195007, 195008, 195009, 195010, 195011, 195012, 195013, 195014,
195015, 195016, 195017, 195018, 195019, 195020, 195021, 195022, 195023, 195024, 195025, 195026, 195027, 195028,
195029, 195030, 195031, 195032, 195033, 195034, 195035, 195036, 195037, 195038, 195039, 195040, 195041, 195042,
195043, 195044, 195045, 195046, 195047, 195048, 195049, 195050, 195051, 195052, 195053, 195054, 195055, 195056,
195057, 195058, 195059, 195060, 195061, 195062, 195063, 195064, 195065, 195066, 195067, 195068, 195069, 195070,
195071, 195072, 195073, 195074, 195075, 195076, 195077, 195078, 195079, 195080, 195081, 195082, 195083, 195084,
195085, 195086, 195087, 195088, 195089, 195090, 195091, 195092, 195093, 195094, 195095, 195096, 195097, 195098,
195099, 195100, 195101
};
struct Decomposition {
const KInt array[4];
const KByte length;
};
constexpr Decomposition decompositionValues[] = {
{{65, 768}, 2}, {{65, 769}, 2}, {{65, 770}, 2}, {{65, 771}, 2}, {{65, 776}, 2}, {{65, 778}, 2}, {{67, 807}, 2},
{{69, 768}, 2}, {{69, 769}, 2}, {{69, 770}, 2}, {{69, 776}, 2}, {{73, 768}, 2}, {{73, 769}, 2}, {{73, 770}, 2},
{{73, 776}, 2}, {{78, 771}, 2}, {{79, 768}, 2}, {{79, 769}, 2}, {{79, 770}, 2}, {{79, 771}, 2}, {{79, 776}, 2},
{{85, 768}, 2}, {{85, 769}, 2}, {{85, 770}, 2}, {{85, 776}, 2}, {{89, 769}, 2}, {{97, 768}, 2}, {{97, 769}, 2},
{{97, 770}, 2}, {{97, 771}, 2}, {{97, 776}, 2}, {{97, 778}, 2}, {{99, 807}, 2}, {{101, 768}, 2}, {{101, 769}, 2},
{{101, 770}, 2}, {{101, 776}, 2}, {{105, 768}, 2}, {{105, 769}, 2}, {{105, 770}, 2}, {{105, 776}, 2}, {{110, 771}, 2},
{{111, 768}, 2}, {{111, 769}, 2}, {{111, 770}, 2}, {{111, 771}, 2}, {{111, 776}, 2}, {{117, 768}, 2}, {{117, 769}, 2},
{{117, 770}, 2}, {{117, 776}, 2}, {{121, 769}, 2}, {{121, 776}, 2}, {{65, 772}, 2}, {{97, 772}, 2}, {{65, 774}, 2},
{{97, 774}, 2}, {{65, 808}, 2}, {{97, 808}, 2}, {{67, 769}, 2}, {{99, 769}, 2}, {{67, 770}, 2}, {{99, 770}, 2},
{{67, 775}, 2}, {{99, 775}, 2}, {{67, 780}, 2}, {{99, 780}, 2}, {{68, 780}, 2}, {{100, 780}, 2}, {{69, 772}, 2},
{{101, 772}, 2}, {{69, 774}, 2}, {{101, 774}, 2}, {{69, 775}, 2}, {{101, 775}, 2}, {{69, 808}, 2}, {{101, 808}, 2},
{{69, 780}, 2}, {{101, 780}, 2}, {{71, 770}, 2}, {{103, 770}, 2}, {{71, 774}, 2}, {{103, 774}, 2}, {{71, 775}, 2},
{{103, 775}, 2}, {{71, 807}, 2}, {{103, 807}, 2}, {{72, 770}, 2}, {{104, 770}, 2}, {{73, 771}, 2}, {{105, 771}, 2},
{{73, 772}, 2}, {{105, 772}, 2}, {{73, 774}, 2}, {{105, 774}, 2}, {{73, 808}, 2}, {{105, 808}, 2}, {{73, 775}, 2},
{{74, 770}, 2}, {{106, 770}, 2}, {{75, 807}, 2}, {{107, 807}, 2}, {{76, 769}, 2}, {{108, 769}, 2}, {{76, 807}, 2},
{{108, 807}, 2}, {{76, 780}, 2}, {{108, 780}, 2}, {{78, 769}, 2}, {{110, 769}, 2}, {{78, 807}, 2}, {{110, 807}, 2},
{{78, 780}, 2}, {{110, 780}, 2}, {{79, 772}, 2}, {{111, 772}, 2}, {{79, 774}, 2}, {{111, 774}, 2}, {{79, 779}, 2},
{{111, 779}, 2}, {{82, 769}, 2}, {{114, 769}, 2}, {{82, 807}, 2}, {{114, 807}, 2}, {{82, 780}, 2}, {{114, 780}, 2},
{{83, 769}, 2}, {{115, 769}, 2}, {{83, 770}, 2}, {{115, 770}, 2}, {{83, 807}, 2}, {{115, 807}, 2}, {{83, 780}, 2},
{{115, 780}, 2}, {{84, 807}, 2}, {{116, 807}, 2}, {{84, 780}, 2}, {{116, 780}, 2}, {{85, 771}, 2}, {{117, 771}, 2},
{{85, 772}, 2}, {{117, 772}, 2}, {{85, 774}, 2}, {{117, 774}, 2}, {{85, 778}, 2}, {{117, 778}, 2}, {{85, 779}, 2},
{{117, 779}, 2}, {{85, 808}, 2}, {{117, 808}, 2}, {{87, 770}, 2}, {{119, 770}, 2}, {{89, 770}, 2}, {{121, 770}, 2},
{{89, 776}, 2}, {{90, 769}, 2}, {{122, 769}, 2}, {{90, 775}, 2}, {{122, 775}, 2}, {{90, 780}, 2}, {{122, 780}, 2},
{{79, 795}, 2}, {{111, 795}, 2}, {{85, 795}, 2}, {{117, 795}, 2}, {{65, 780}, 2}, {{97, 780}, 2}, {{73, 780}, 2},
{{105, 780}, 2}, {{79, 780}, 2}, {{111, 780}, 2}, {{85, 780}, 2}, {{117, 780}, 2}, {{85, 776, 772}, 3},
{{117, 776, 772}, 3}, {{85, 776, 769}, 3}, {{117, 776, 769}, 3}, {{85, 776, 780}, 3}, {{117, 776, 780}, 3},
{{85, 776, 768}, 3}, {{117, 776, 768}, 3}, {{65, 776, 772}, 3}, {{97, 776, 772}, 3}, {{65, 775, 772}, 3},
{{97, 775, 772}, 3}, {{198, 772}, 2}, {{230, 772}, 2}, {{71, 780}, 2}, {{103, 780}, 2}, {{75, 780}, 2},
{{107, 780}, 2}, {{79, 808}, 2}, {{111, 808}, 2}, {{79, 808, 772}, 3}, {{111, 808, 772}, 3}, {{439, 780}, 2},
{{658, 780}, 2}, {{106, 780}, 2}, {{71, 769}, 2}, {{103, 769}, 2}, {{78, 768}, 2}, {{110, 768}, 2},
{{65, 778, 769}, 3}, {{97, 778, 769}, 3}, {{198, 769}, 2}, {{230, 769}, 2}, {{216, 769}, 2}, {{248, 769}, 2},
{{65, 783}, 2}, {{97, 783}, 2}, {{65, 785}, 2}, {{97, 785}, 2}, {{69, 783}, 2}, {{101, 783}, 2}, {{69, 785}, 2},
{{101, 785}, 2}, {{73, 783}, 2}, {{105, 783}, 2}, {{73, 785}, 2}, {{105, 785}, 2}, {{79, 783}, 2}, {{111, 783}, 2},
{{79, 785}, 2}, {{111, 785}, 2}, {{82, 783}, 2}, {{114, 783}, 2}, {{82, 785}, 2}, {{114, 785}, 2}, {{85, 783}, 2},
{{117, 783}, 2}, {{85, 785}, 2}, {{117, 785}, 2}, {{83, 806}, 2}, {{115, 806}, 2}, {{84, 806}, 2}, {{116, 806}, 2},
{{72, 780}, 2}, {{104, 780}, 2}, {{65, 775}, 2}, {{97, 775}, 2}, {{69, 807}, 2}, {{101, 807}, 2}, {{79, 776, 772}, 3},
{{111, 776, 772}, 3}, {{79, 771, 772}, 3}, {{111, 771, 772}, 3}, {{79, 775}, 2}, {{111, 775}, 2}, {{79, 775, 772}, 3},
{{111, 775, 772}, 3}, {{89, 772}, 2}, {{121, 772}, 2}, {{768}, 1}, {{769}, 1}, {{787}, 1}, {{776, 769}, 2},
{{697}, 1}, {{59}, 1}, {{168, 769}, 2}, {{913, 769}, 2}, {{183}, 1}, {{917, 769}, 2}, {{919, 769}, 2},
{{921, 769}, 2}, {{927, 769}, 2}, {{933, 769}, 2}, {{937, 769}, 2}, {{953, 776, 769}, 3}, {{921, 776}, 2},
{{933, 776}, 2}, {{945, 769}, 2}, {{949, 769}, 2}, {{951, 769}, 2}, {{953, 769}, 2}, {{965, 776, 769}, 3},
{{953, 776}, 2}, {{965, 776}, 2}, {{959, 769}, 2}, {{965, 769}, 2}, {{969, 769}, 2}, {{978, 769}, 2}, {{978, 776}, 2},
{{1045, 768}, 2}, {{1045, 776}, 2}, {{1043, 769}, 2}, {{1030, 776}, 2}, {{1050, 769}, 2}, {{1048, 768}, 2},
{{1059, 774}, 2}, {{1048, 774}, 2}, {{1080, 774}, 2}, {{1077, 768}, 2}, {{1077, 776}, 2}, {{1075, 769}, 2},
{{1110, 776}, 2}, {{1082, 769}, 2}, {{1080, 768}, 2}, {{1091, 774}, 2}, {{1140, 783}, 2}, {{1141, 783}, 2},
{{1046, 774}, 2}, {{1078, 774}, 2}, {{1040, 774}, 2}, {{1072, 774}, 2}, {{1040, 776}, 2}, {{1072, 776}, 2},
{{1045, 774}, 2}, {{1077, 774}, 2}, {{1240, 776}, 2}, {{1241, 776}, 2}, {{1046, 776}, 2}, {{1078, 776}, 2},
{{1047, 776}, 2}, {{1079, 776}, 2}, {{1048, 772}, 2}, {{1080, 772}, 2}, {{1048, 776}, 2}, {{1080, 776}, 2},
{{1054, 776}, 2}, {{1086, 776}, 2}, {{1256, 776}, 2}, {{1257, 776}, 2}, {{1069, 776}, 2}, {{1101, 776}, 2},
{{1059, 772}, 2}, {{1091, 772}, 2}, {{1059, 776}, 2}, {{1091, 776}, 2}, {{1059, 779}, 2}, {{1091, 779}, 2},
{{1063, 776}, 2}, {{1095, 776}, 2}, {{1067, 776}, 2}, {{1099, 776}, 2}, {{1575, 1619}, 2}, {{1575, 1620}, 2},
{{1608, 1620}, 2}, {{1575, 1621}, 2}, {{1610, 1620}, 2}, {{1749, 1620}, 2}, {{1729, 1620}, 2}, {{1746, 1620}, 2},
{{2344, 2364}, 2}, {{2352, 2364}, 2}, {{2355, 2364}, 2}, {{2325, 2364}, 2}, {{2326, 2364}, 2}, {{2327, 2364}, 2},
{{2332, 2364}, 2}, {{2337, 2364}, 2}, {{2338, 2364}, 2}, {{2347, 2364}, 2}, {{2351, 2364}, 2}, {{2503, 2494}, 2},
{{2503, 2519}, 2}, {{2465, 2492}, 2}, {{2466, 2492}, 2}, {{2479, 2492}, 2}, {{2610, 2620}, 2}, {{2616, 2620}, 2},
{{2582, 2620}, 2}, {{2583, 2620}, 2}, {{2588, 2620}, 2}, {{2603, 2620}, 2}, {{2887, 2902}, 2}, {{2887, 2878}, 2},
{{2887, 2903}, 2}, {{2849, 2876}, 2}, {{2850, 2876}, 2}, {{2962, 3031}, 2}, {{3014, 3006}, 2}, {{3015, 3006}, 2},
{{3014, 3031}, 2}, {{3142, 3158}, 2}, {{3263, 3285}, 2}, {{3270, 3285}, 2}, {{3270, 3286}, 2}, {{3270, 3266}, 2},
{{3270, 3266, 3285}, 3}, {{3398, 3390}, 2}, {{3399, 3390}, 2}, {{3398, 3415}, 2}, {{3545, 3530}, 2},
{{3545, 3535}, 2}, {{3545, 3535, 3530}, 3}, {{3545, 3551}, 2}, {{3906, 4023}, 2}, {{3916, 4023}, 2},
{{3921, 4023}, 2}, {{3926, 4023}, 2}, {{3931, 4023}, 2}, {{3904, 4021}, 2}, {{3953, 3954}, 2}, {{3953, 3956}, 2},
{{4018, 3968}, 2}, {{4019, 3968}, 2}, {{3953, 3968}, 2}, {{3986, 4023}, 2}, {{3996, 4023}, 2}, {{4001, 4023}, 2},
{{4006, 4023}, 2}, {{4011, 4023}, 2}, {{3984, 4021}, 2}, {{4133, 4142}, 2}, {{65, 805}, 2}, {{97, 805}, 2},
{{66, 775}, 2}, {{98, 775}, 2}, {{66, 803}, 2}, {{98, 803}, 2}, {{66, 817}, 2}, {{98, 817}, 2}, {{67, 807, 769}, 3},
{{99, 807, 769}, 3}, {{68, 775}, 2}, {{100, 775}, 2}, {{68, 803}, 2}, {{100, 803}, 2}, {{68, 817}, 2},
{{100, 817}, 2}, {{68, 807}, 2}, {{100, 807}, 2}, {{68, 813}, 2}, {{100, 813}, 2}, {{69, 772, 768}, 3},
{{101, 772, 768}, 3}, {{69, 772, 769}, 3}, {{101, 772, 769}, 3}, {{69, 813}, 2}, {{101, 813}, 2}, {{69, 816}, 2},
{{101, 816}, 2}, {{69, 807, 774}, 3}, {{101, 807, 774}, 3}, {{70, 775}, 2}, {{102, 775}, 2}, {{71, 772}, 2},
{{103, 772}, 2}, {{72, 775}, 2}, {{104, 775}, 2}, {{72, 803}, 2}, {{104, 803}, 2}, {{72, 776}, 2}, {{104, 776}, 2},
{{72, 807}, 2}, {{104, 807}, 2}, {{72, 814}, 2}, {{104, 814}, 2}, {{73, 816}, 2}, {{105, 816}, 2},
{{73, 776, 769}, 3}, {{105, 776, 769}, 3}, {{75, 769}, 2}, {{107, 769}, 2}, {{75, 803}, 2}, {{107, 803}, 2},
{{75, 817}, 2}, {{107, 817}, 2}, {{76, 803}, 2}, {{108, 803}, 2}, {{76, 803, 772}, 3}, {{108, 803, 772}, 3},
{{76, 817}, 2}, {{108, 817}, 2}, {{76, 813}, 2}, {{108, 813}, 2}, {{77, 769}, 2}, {{109, 769}, 2}, {{77, 775}, 2},
{{109, 775}, 2}, {{77, 803}, 2}, {{109, 803}, 2}, {{78, 775}, 2}, {{110, 775}, 2}, {{78, 803}, 2}, {{110, 803}, 2},
{{78, 817}, 2}, {{110, 817}, 2}, {{78, 813}, 2}, {{110, 813}, 2}, {{79, 771, 769}, 3}, {{111, 771, 769}, 3},
{{79, 771, 776}, 3}, {{111, 771, 776}, 3}, {{79, 772, 768}, 3}, {{111, 772, 768}, 3}, {{79, 772, 769}, 3},
{{111, 772, 769}, 3}, {{80, 769}, 2}, {{112, 769}, 2}, {{80, 775}, 2}, {{112, 775}, 2}, {{82, 775}, 2},
{{114, 775}, 2}, {{82, 803}, 2}, {{114, 803}, 2}, {{82, 803, 772}, 3}, {{114, 803, 772}, 3}, {{82, 817}, 2},
{{114, 817}, 2}, {{83, 775}, 2}, {{115, 775}, 2}, {{83, 803}, 2}, {{115, 803}, 2}, {{83, 769, 775}, 3},
{{115, 769, 775}, 3}, {{83, 780, 775}, 3}, {{115, 780, 775}, 3}, {{83, 803, 775}, 3}, {{115, 803, 775}, 3},
{{84, 775}, 2}, {{116, 775}, 2}, {{84, 803}, 2}, {{116, 803}, 2}, {{84, 817}, 2}, {{116, 817}, 2}, {{84, 813}, 2},
{{116, 813}, 2}, {{85, 804}, 2}, {{117, 804}, 2}, {{85, 816}, 2}, {{117, 816}, 2}, {{85, 813}, 2}, {{117, 813}, 2},
{{85, 771, 769}, 3}, {{117, 771, 769}, 3}, {{85, 772, 776}, 3}, {{117, 772, 776}, 3}, {{86, 771}, 2}, {{118, 771}, 2},
{{86, 803}, 2}, {{118, 803}, 2}, {{87, 768}, 2}, {{119, 768}, 2}, {{87, 769}, 2}, {{119, 769}, 2}, {{87, 776}, 2},
{{119, 776}, 2}, {{87, 775}, 2}, {{119, 775}, 2}, {{87, 803}, 2}, {{119, 803}, 2}, {{88, 775}, 2}, {{120, 775}, 2},
{{88, 776}, 2}, {{120, 776}, 2}, {{89, 775}, 2}, {{121, 775}, 2}, {{90, 770}, 2}, {{122, 770}, 2}, {{90, 803}, 2},
{{122, 803}, 2}, {{90, 817}, 2}, {{122, 817}, 2}, {{104, 817}, 2}, {{116, 776}, 2}, {{119, 778}, 2}, {{121, 778}, 2},
{{383, 775}, 2}, {{65, 803}, 2}, {{97, 803}, 2}, {{65, 777}, 2}, {{97, 777}, 2}, {{65, 770, 769}, 3},
{{97, 770, 769}, 3}, {{65, 770, 768}, 3}, {{97, 770, 768}, 3}, {{65, 770, 777}, 3}, {{97, 770, 777}, 3},
{{65, 770, 771}, 3}, {{97, 770, 771}, 3}, {{65, 803, 770}, 3}, {{97, 803, 770}, 3}, {{65, 774, 769}, 3},
{{97, 774, 769}, 3}, {{65, 774, 768}, 3}, {{97, 774, 768}, 3}, {{65, 774, 777}, 3}, {{97, 774, 777}, 3},
{{65, 774, 771}, 3}, {{97, 774, 771}, 3}, {{65, 803, 774}, 3}, {{97, 803, 774}, 3}, {{69, 803}, 2}, {{101, 803}, 2},
{{69, 777}, 2}, {{101, 777}, 2}, {{69, 771}, 2}, {{101, 771}, 2}, {{69, 770, 769}, 3}, {{101, 770, 769}, 3},
{{69, 770, 768}, 3}, {{101, 770, 768}, 3}, {{69, 770, 777}, 3}, {{101, 770, 777}, 3}, {{69, 770, 771}, 3},
{{101, 770, 771}, 3}, {{69, 803, 770}, 3}, {{101, 803, 770}, 3}, {{73, 777}, 2}, {{105, 777}, 2}, {{73, 803}, 2},
{{105, 803}, 2}, {{79, 803}, 2}, {{111, 803}, 2}, {{79, 777}, 2}, {{111, 777}, 2}, {{79, 770, 769}, 3},
{{111, 770, 769}, 3}, {{79, 770, 768}, 3}, {{111, 770, 768}, 3}, {{79, 770, 777}, 3}, {{111, 770, 777}, 3},
{{79, 770, 771}, 3}, {{111, 770, 771}, 3}, {{79, 803, 770}, 3}, {{111, 803, 770}, 3}, {{79, 795, 769}, 3},
{{111, 795, 769}, 3}, {{79, 795, 768}, 3}, {{111, 795, 768}, 3}, {{79, 795, 777}, 3}, {{111, 795, 777}, 3},
{{79, 795, 771}, 3}, {{111, 795, 771}, 3}, {{79, 795, 803}, 3}, {{111, 795, 803}, 3}, {{85, 803}, 2}, {{117, 803}, 2},
{{85, 777}, 2}, {{117, 777}, 2}, {{85, 795, 769}, 3}, {{117, 795, 769}, 3}, {{85, 795, 768}, 3}, {{117, 795, 768}, 3},
{{85, 795, 777}, 3}, {{117, 795, 777}, 3}, {{85, 795, 771}, 3}, {{117, 795, 771}, 3}, {{85, 795, 803}, 3},
{{117, 795, 803}, 3}, {{89, 768}, 2}, {{121, 768}, 2}, {{89, 803}, 2}, {{121, 803}, 2}, {{89, 777}, 2},
{{121, 777}, 2}, {{89, 771}, 2}, {{121, 771}, 2}, {{945, 787}, 2}, {{945, 788}, 2}, {{945, 787, 768}, 3},
{{945, 788, 768}, 3}, {{945, 787, 769}, 3}, {{945, 788, 769}, 3}, {{945, 787, 834}, 3}, {{945, 788, 834}, 3},
{{913, 787}, 2}, {{913, 788}, 2}, {{913, 787, 768}, 3}, {{913, 788, 768}, 3}, {{913, 787, 769}, 3},
{{913, 788, 769}, 3}, {{913, 787, 834}, 3}, {{913, 788, 834}, 3}, {{949, 787}, 2}, {{949, 788}, 2},
{{949, 787, 768}, 3}, {{949, 788, 768}, 3}, {{949, 787, 769}, 3}, {{949, 788, 769}, 3}, {{917, 787}, 2},
{{917, 788}, 2}, {{917, 787, 768}, 3}, {{917, 788, 768}, 3}, {{917, 787, 769}, 3}, {{917, 788, 769}, 3},
{{951, 787}, 2}, {{951, 788}, 2}, {{951, 787, 768}, 3}, {{951, 788, 768}, 3}, {{951, 787, 769}, 3},
{{951, 788, 769}, 3}, {{951, 787, 834}, 3}, {{951, 788, 834}, 3}, {{919, 787}, 2}, {{919, 788}, 2},
{{919, 787, 768}, 3}, {{919, 788, 768}, 3}, {{919, 787, 769}, 3}, {{919, 788, 769}, 3}, {{919, 787, 834}, 3},
{{919, 788, 834}, 3}, {{953, 787}, 2}, {{953, 788}, 2}, {{953, 787, 768}, 3}, {{953, 788, 768}, 3},
{{953, 787, 769}, 3}, {{953, 788, 769}, 3}, {{953, 787, 834}, 3}, {{953, 788, 834}, 3}, {{921, 787}, 2},
{{921, 788}, 2}, {{921, 787, 768}, 3}, {{921, 788, 768}, 3}, {{921, 787, 769}, 3}, {{921, 788, 769}, 3},
{{921, 787, 834}, 3}, {{921, 788, 834}, 3}, {{959, 787}, 2}, {{959, 788}, 2}, {{959, 787, 768}, 3},
{{959, 788, 768}, 3}, {{959, 787, 769}, 3}, {{959, 788, 769}, 3}, {{927, 787}, 2}, {{927, 788}, 2},
{{927, 787, 768}, 3}, {{927, 788, 768}, 3}, {{927, 787, 769}, 3}, {{927, 788, 769}, 3}, {{965, 787}, 2},
{{965, 788}, 2}, {{965, 787, 768}, 3}, {{965, 788, 768}, 3}, {{965, 787, 769}, 3}, {{965, 788, 769}, 3},
{{965, 787, 834}, 3}, {{965, 788, 834}, 3}, {{933, 788}, 2}, {{933, 788, 768}, 3}, {{933, 788, 769}, 3},
{{933, 788, 834}, 3}, {{969, 787}, 2}, {{969, 788}, 2}, {{969, 787, 768}, 3}, {{969, 788, 768}, 3},
{{969, 787, 769}, 3}, {{969, 788, 769}, 3}, {{969, 787, 834}, 3}, {{969, 788, 834}, 3}, {{937, 787}, 2},
{{937, 788}, 2}, {{937, 787, 768}, 3}, {{937, 788, 768}, 3}, {{937, 787, 769}, 3}, {{937, 788, 769}, 3},
{{937, 787, 834}, 3}, {{937, 788, 834}, 3}, {{945, 768}, 2}, {{945, 769}, 2}, {{949, 768}, 2}, {{949, 769}, 2},
{{951, 768}, 2}, {{951, 769}, 2}, {{953, 768}, 2}, {{953, 769}, 2}, {{959, 768}, 2}, {{959, 769}, 2}, {{965, 768}, 2},
{{965, 769}, 2}, {{969, 768}, 2}, {{969, 769}, 2}, {{945, 787, 837}, 3}, {{945, 788, 837}, 3},
{{945, 787, 768, 837}, 4}, {{945, 788, 768, 837}, 4}, {{945, 787, 769, 837}, 4}, {{945, 788, 769, 837}, 4},
{{945, 787, 834, 837}, 4}, {{945, 788, 834, 837}, 4}, {{913, 787, 837}, 3}, {{913, 788, 837}, 3},
{{913, 787, 768, 837}, 4}, {{913, 788, 768, 837}, 4}, {{913, 787, 769, 837}, 4}, {{913, 788, 769, 837}, 4},
{{913, 787, 834, 837}, 4}, {{913, 788, 834, 837}, 4}, {{951, 787, 837}, 3}, {{951, 788, 837}, 3},
{{951, 787, 768, 837}, 4}, {{951, 788, 768, 837}, 4}, {{951, 787, 769, 837}, 4}, {{951, 788, 769, 837}, 4},
{{951, 787, 834, 837}, 4}, {{951, 788, 834, 837}, 4}, {{919, 787, 837}, 3}, {{919, 788, 837}, 3},
{{919, 787, 768, 837}, 4}, {{919, 788, 768, 837}, 4}, {{919, 787, 769, 837}, 4}, {{919, 788, 769, 837}, 4},
{{919, 787, 834, 837}, 4}, {{919, 788, 834, 837}, 4}, {{969, 787, 837}, 3}, {{969, 788, 837}, 3},
{{969, 787, 768, 837}, 4}, {{969, 788, 768, 837}, 4}, {{969, 787, 769, 837}, 4}, {{969, 788, 769, 837}, 4},
{{969, 787, 834, 837}, 4}, {{969, 788, 834, 837}, 4}, {{937, 787, 837}, 3}, {{937, 788, 837}, 3},
{{937, 787, 768, 837}, 4}, {{937, 788, 768, 837}, 4}, {{937, 787, 769, 837}, 4}, {{937, 788, 769, 837}, 4},
{{937, 787, 834, 837}, 4}, {{937, 788, 834, 837}, 4}, {{945, 774}, 2}, {{945, 772}, 2}, {{945, 768, 837}, 3},
{{945, 837}, 2}, {{945, 769, 837}, 3}, {{945, 834}, 2}, {{945, 834, 837}, 3}, {{913, 774}, 2}, {{913, 772}, 2},
{{913, 768}, 2}, {{913, 769}, 2}, {{913, 837}, 2}, {{953}, 1}, {{168, 834}, 2}, {{951, 768, 837}, 3}, {{951, 837}, 2},
{{951, 769, 837}, 3}, {{951, 834}, 2}, {{951, 834, 837}, 3}, {{917, 768}, 2}, {{917, 769}, 2}, {{919, 768}, 2},
{{919, 769}, 2}, {{919, 837}, 2}, {{8127, 768}, 2}, {{8127, 769}, 2}, {{8127, 834}, 2}, {{953, 774}, 2},
{{953, 772}, 2}, {{953, 776, 768}, 3}, {{953, 776, 769}, 3}, {{953, 834}, 2}, {{953, 776, 834}, 3}, {{921, 774}, 2},
{{921, 772}, 2}, {{921, 768}, 2}, {{921, 769}, 2}, {{8190, 768}, 2}, {{8190, 769}, 2}, {{8190, 834}, 2},
{{965, 774}, 2}, {{965, 772}, 2}, {{965, 776, 768}, 3}, {{965, 776, 769}, 3}, {{961, 787}, 2}, {{961, 788}, 2},
{{965, 834}, 2}, {{965, 776, 834}, 3}, {{933, 774}, 2}, {{933, 772}, 2}, {{933, 768}, 2}, {{933, 769}, 2},
{{929, 788}, 2}, {{168, 768}, 2}, {{168, 769}, 2}, {{96}, 1}, {{969, 768, 837}, 3}, {{969, 837}, 2},
{{969, 769, 837}, 3}, {{969, 834}, 2}, {{969, 834, 837}, 3}, {{927, 768}, 2}, {{927, 769}, 2}, {{937, 768}, 2},
{{937, 769}, 2}, {{937, 837}, 2}, {{180}, 1}, {{8194}, 1}, {{8195}, 1}, {{937}, 1}, {{75}, 1}, {{65, 778}, 2},
{{8592, 824}, 2}, {{8594, 824}, 2}, {{8596, 824}, 2}, {{8656, 824}, 2}, {{8660, 824}, 2}, {{8658, 824}, 2},
{{8707, 824}, 2}, {{8712, 824}, 2}, {{8715, 824}, 2}, {{8739, 824}, 2}, {{8741, 824}, 2}, {{8764, 824}, 2},
{{8771, 824}, 2}, {{8773, 824}, 2}, {{8776, 824}, 2}, {{61, 824}, 2}, {{8801, 824}, 2}, {{8781, 824}, 2},
{{60, 824}, 2}, {{62, 824}, 2}, {{8804, 824}, 2}, {{8805, 824}, 2}, {{8818, 824}, 2}, {{8819, 824}, 2},
{{8822, 824}, 2}, {{8823, 824}, 2}, {{8826, 824}, 2}, {{8827, 824}, 2}, {{8834, 824}, 2}, {{8835, 824}, 2},
{{8838, 824}, 2}, {{8839, 824}, 2}, {{8866, 824}, 2}, {{8872, 824}, 2}, {{8873, 824}, 2}, {{8875, 824}, 2},
{{8828, 824}, 2}, {{8829, 824}, 2}, {{8849, 824}, 2}, {{8850, 824}, 2}, {{8882, 824}, 2}, {{8883, 824}, 2},
{{8884, 824}, 2}, {{8885, 824}, 2}, {{12296}, 1}, {{12297}, 1}, {{10973, 824}, 2}, {{12363, 12441}, 2},
{{12365, 12441}, 2}, {{12367, 12441}, 2}, {{12369, 12441}, 2}, {{12371, 12441}, 2}, {{12373, 12441}, 2},
{{12375, 12441}, 2}, {{12377, 12441}, 2}, {{12379, 12441}, 2}, {{12381, 12441}, 2}, {{12383, 12441}, 2},
{{12385, 12441}, 2}, {{12388, 12441}, 2}, {{12390, 12441}, 2}, {{12392, 12441}, 2}, {{12399, 12441}, 2},
{{12399, 12442}, 2}, {{12402, 12441}, 2}, {{12402, 12442}, 2}, {{12405, 12441}, 2}, {{12405, 12442}, 2},
{{12408, 12441}, 2}, {{12408, 12442}, 2}, {{12411, 12441}, 2}, {{12411, 12442}, 2}, {{12358, 12441}, 2},
{{12445, 12441}, 2}, {{12459, 12441}, 2}, {{12461, 12441}, 2}, {{12463, 12441}, 2}, {{12465, 12441}, 2},
{{12467, 12441}, 2}, {{12469, 12441}, 2}, {{12471, 12441}, 2}, {{12473, 12441}, 2}, {{12475, 12441}, 2},
{{12477, 12441}, 2}, {{12479, 12441}, 2}, {{12481, 12441}, 2}, {{12484, 12441}, 2}, {{12486, 12441}, 2},
{{12488, 12441}, 2}, {{12495, 12441}, 2}, {{12495, 12442}, 2}, {{12498, 12441}, 2}, {{12498, 12442}, 2},
{{12501, 12441}, 2}, {{12501, 12442}, 2}, {{12504, 12441}, 2}, {{12504, 12442}, 2}, {{12507, 12441}, 2},
{{12507, 12442}, 2}, {{12454, 12441}, 2}, {{12527, 12441}, 2}, {{12528, 12441}, 2}, {{12529, 12441}, 2},
{{12530, 12441}, 2}, {{12541, 12441}, 2}, {{35912}, 1}, {{26356}, 1}, {{36554}, 1}, {{36040}, 1}, {{28369}, 1},
{{20018}, 1}, {{21477}, 1}, {{40860}, 1}, {{40860}, 1}, {{22865}, 1}, {{37329}, 1}, {{21895}, 1}, {{22856}, 1},
{{25078}, 1}, {{30313}, 1}, {{32645}, 1}, {{34367}, 1}, {{34746}, 1}, {{35064}, 1}, {{37007}, 1}, {{27138}, 1},
{{27931}, 1}, {{28889}, 1}, {{29662}, 1}, {{33853}, 1}, {{37226}, 1}, {{39409}, 1}, {{20098}, 1}, {{21365}, 1},
{{27396}, 1}, {{29211}, 1}, {{34349}, 1}, {{40478}, 1}, {{23888}, 1}, {{28651}, 1}, {{34253}, 1}, {{35172}, 1},
{{25289}, 1}, {{33240}, 1}, {{34847}, 1}, {{24266}, 1}, {{26391}, 1}, {{28010}, 1}, {{29436}, 1}, {{37070}, 1},
{{20358}, 1}, {{20919}, 1}, {{21214}, 1}, {{25796}, 1}, {{27347}, 1}, {{29200}, 1}, {{30439}, 1}, {{32769}, 1},
{{34310}, 1}, {{34396}, 1}, {{36335}, 1}, {{38706}, 1}, {{39791}, 1}, {{40442}, 1}, {{30860}, 1}, {{31103}, 1},
{{32160}, 1}, {{33737}, 1}, {{37636}, 1}, {{40575}, 1}, {{35542}, 1}, {{22751}, 1}, {{24324}, 1}, {{31840}, 1},
{{32894}, 1}, {{29282}, 1}, {{30922}, 1}, {{36034}, 1}, {{38647}, 1}, {{22744}, 1}, {{23650}, 1}, {{27155}, 1},
{{28122}, 1}, {{28431}, 1}, {{32047}, 1}, {{32311}, 1}, {{38475}, 1}, {{21202}, 1}, {{32907}, 1}, {{20956}, 1},
{{20940}, 1}, {{31260}, 1}, {{32190}, 1}, {{33777}, 1}, {{38517}, 1}, {{35712}, 1}, {{25295}, 1}, {{27138}, 1},
{{35582}, 1}, {{20025}, 1}, {{23527}, 1}, {{24594}, 1}, {{29575}, 1}, {{30064}, 1}, {{21271}, 1}, {{30971}, 1},
{{20415}, 1}, {{24489}, 1}, {{19981}, 1}, {{27852}, 1}, {{25976}, 1}, {{32034}, 1}, {{21443}, 1}, {{22622}, 1},
{{30465}, 1}, {{33865}, 1}, {{35498}, 1}, {{27578}, 1}, {{36784}, 1}, {{27784}, 1}, {{25342}, 1}, {{33509}, 1},
{{25504}, 1}, {{30053}, 1}, {{20142}, 1}, {{20841}, 1}, {{20937}, 1}, {{26753}, 1}, {{31975}, 1}, {{33391}, 1},
{{35538}, 1}, {{37327}, 1}, {{21237}, 1}, {{21570}, 1}, {{22899}, 1}, {{24300}, 1}, {{26053}, 1}, {{28670}, 1},
{{31018}, 1}, {{38317}, 1}, {{39530}, 1}, {{40599}, 1}, {{40654}, 1}, {{21147}, 1}, {{26310}, 1}, {{27511}, 1},
{{36706}, 1}, {{24180}, 1}, {{24976}, 1}, {{25088}, 1}, {{25754}, 1}, {{28451}, 1}, {{29001}, 1}, {{29833}, 1},
{{31178}, 1}, {{32244}, 1}, {{32879}, 1}, {{36646}, 1}, {{34030}, 1}, {{36899}, 1}, {{37706}, 1}, {{21015}, 1},
{{21155}, 1}, {{21693}, 1}, {{28872}, 1}, {{35010}, 1}, {{35498}, 1}, {{24265}, 1}, {{24565}, 1}, {{25467}, 1},
{{27566}, 1}, {{31806}, 1}, {{29557}, 1}, {{20196}, 1}, {{22265}, 1}, {{23527}, 1}, {{23994}, 1}, {{24604}, 1},
{{29618}, 1}, {{29801}, 1}, {{32666}, 1}, {{32838}, 1}, {{37428}, 1}, {{38646}, 1}, {{38728}, 1}, {{38936}, 1},
{{20363}, 1}, {{31150}, 1}, {{37300}, 1}, {{38584}, 1}, {{24801}, 1}, {{20102}, 1}, {{20698}, 1}, {{23534}, 1},
{{23615}, 1}, {{26009}, 1}, {{27138}, 1}, {{29134}, 1}, {{30274}, 1}, {{34044}, 1}, {{36988}, 1}, {{40845}, 1},
{{26248}, 1}, {{38446}, 1}, {{21129}, 1}, {{26491}, 1}, {{26611}, 1}, {{27969}, 1}, {{28316}, 1}, {{29705}, 1},
{{30041}, 1}, {{30827}, 1}, {{32016}, 1}, {{39006}, 1}, {{20845}, 1}, {{25134}, 1}, {{38520}, 1}, {{20523}, 1},
{{23833}, 1}, {{28138}, 1}, {{36650}, 1}, {{24459}, 1}, {{24900}, 1}, {{26647}, 1}, {{29575}, 1}, {{38534}, 1},
{{21033}, 1}, {{21519}, 1}, {{23653}, 1}, {{26131}, 1}, {{26446}, 1}, {{26792}, 1}, {{27877}, 1}, {{29702}, 1},
{{30178}, 1}, {{32633}, 1}, {{35023}, 1}, {{35041}, 1}, {{37324}, 1}, {{38626}, 1}, {{21311}, 1}, {{28346}, 1},
{{21533}, 1}, {{29136}, 1}, {{29848}, 1}, {{34298}, 1}, {{38563}, 1}, {{40023}, 1}, {{40607}, 1}, {{26519}, 1},
{{28107}, 1}, {{33256}, 1}, {{31435}, 1}, {{31520}, 1}, {{31890}, 1}, {{29376}, 1}, {{28825}, 1}, {{35672}, 1},
{{20160}, 1}, {{33590}, 1}, {{21050}, 1}, {{20999}, 1}, {{24230}, 1}, {{25299}, 1}, {{31958}, 1}, {{23429}, 1},
{{27934}, 1}, {{26292}, 1}, {{36667}, 1}, {{34892}, 1}, {{38477}, 1}, {{35211}, 1}, {{24275}, 1}, {{20800}, 1},
{{21952}, 1}, {{22618}, 1}, {{26228}, 1}, {{20958}, 1}, {{29482}, 1}, {{30410}, 1}, {{31036}, 1}, {{31070}, 1},
{{31077}, 1}, {{31119}, 1}, {{38742}, 1}, {{31934}, 1}, {{32701}, 1}, {{34322}, 1}, {{35576}, 1}, {{36920}, 1},
{{37117}, 1}, {{39151}, 1}, {{39164}, 1}, {{39208}, 1}, {{40372}, 1}, {{20398}, 1}, {{20711}, 1}, {{20813}, 1},
{{21193}, 1}, {{21220}, 1}, {{21329}, 1}, {{21917}, 1}, {{22022}, 1}, {{22120}, 1}, {{22592}, 1}, {{22696}, 1},
{{23652}, 1}, {{23662}, 1}, {{24724}, 1}, {{24936}, 1}, {{24974}, 1}, {{25074}, 1}, {{25935}, 1}, {{26082}, 1},
{{26257}, 1}, {{26757}, 1}, {{28023}, 1}, {{28186}, 1}, {{28450}, 1}, {{29038}, 1}, {{29227}, 1}, {{29730}, 1},
{{30865}, 1}, {{31038}, 1}, {{31049}, 1}, {{31048}, 1}, {{31056}, 1}, {{31062}, 1}, {{31069}, 1}, {{31117}, 1},
{{31118}, 1}, {{31296}, 1}, {{31361}, 1}, {{31680}, 1}, {{32244}, 1}, {{32265}, 1}, {{32321}, 1}, {{32626}, 1},
{{32773}, 1}, {{33261}, 1}, {{33401}, 1}, {{33401}, 1}, {{33879}, 1}, {{35088}, 1}, {{35222}, 1}, {{35585}, 1},
{{35641}, 1}, {{36051}, 1}, {{36104}, 1}, {{36790}, 1}, {{36920}, 1}, {{38627}, 1}, {{38911}, 1}, {{38971}, 1},
{{20006}, 1}, {{20917}, 1}, {{20840}, 1}, {{20352}, 1}, {{20805}, 1}, {{20864}, 1}, {{21191}, 1}, {{21242}, 1},
{{21917}, 1}, {{21845}, 1}, {{21913}, 1}, {{21986}, 1}, {{22618}, 1}, {{22707}, 1}, {{22852}, 1}, {{22868}, 1},
{{23138}, 1}, {{23336}, 1}, {{24274}, 1}, {{24281}, 1}, {{24425}, 1}, {{24493}, 1}, {{24792}, 1}, {{24910}, 1},
{{24840}, 1}, {{24974}, 1}, {{24928}, 1}, {{25074}, 1}, {{25140}, 1}, {{25540}, 1}, {{25628}, 1}, {{25682}, 1},
{{25942}, 1}, {{26228}, 1}, {{26391}, 1}, {{26395}, 1}, {{26454}, 1}, {{27513}, 1}, {{27578}, 1}, {{27969}, 1},
{{28379}, 1}, {{28363}, 1}, {{28450}, 1}, {{28702}, 1}, {{29038}, 1}, {{30631}, 1}, {{29237}, 1}, {{29359}, 1},
{{29482}, 1}, {{29809}, 1}, {{29958}, 1}, {{30011}, 1}, {{30237}, 1}, {{30239}, 1}, {{30410}, 1}, {{30427}, 1},
{{30452}, 1}, {{30538}, 1}, {{30528}, 1}, {{30924}, 1}, {{31409}, 1}, {{31680}, 1}, {{31867}, 1}, {{32091}, 1},
{{32244}, 1}, {{32574}, 1}, {{32773}, 1}, {{33618}, 1}, {{33775}, 1}, {{34681}, 1}, {{35137}, 1}, {{35206}, 1},
{{35222}, 1}, {{35519}, 1}, {{35576}, 1}, {{35531}, 1}, {{35585}, 1}, {{35582}, 1}, {{35565}, 1}, {{35641}, 1},
{{35722}, 1}, {{36104}, 1}, {{36664}, 1}, {{36978}, 1}, {{37273}, 1}, {{37494}, 1}, {{38524}, 1}, {{38627}, 1},
{{38742}, 1}, {{38875}, 1}, {{38911}, 1}, {{38923}, 1}, {{38971}, 1}, {{39698}, 1}, {{40860}, 1}, {{141386}, 1},
{{141380}, 1}, {{144341}, 1}, {{15261}, 1}, {{16408}, 1}, {{16441}, 1}, {{152137}, 1}, {{154832}, 1}, {{163539}, 1},
{{40771}, 1}, {{40846}, 1}, {{1497, 1460}, 2}, {{1522, 1463}, 2}, {{1513, 1473}, 2}, {{1513, 1474}, 2},
{{1513, 1468, 1473}, 3}, {{1513, 1468, 1474}, 3}, {{1488, 1463}, 2}, {{1488, 1464}, 2}, {{1488, 1468}, 2},
{{1489, 1468}, 2}, {{1490, 1468}, 2}, {{1491, 1468}, 2}, {{1492, 1468}, 2}, {{1493, 1468}, 2}, {{1494, 1468}, 2},
{{1496, 1468}, 2}, {{1497, 1468}, 2}, {{1498, 1468}, 2}, {{1499, 1468}, 2}, {{1500, 1468}, 2}, {{1502, 1468}, 2},
{{1504, 1468}, 2}, {{1505, 1468}, 2}, {{1507, 1468}, 2}, {{1508, 1468}, 2}, {{1510, 1468}, 2}, {{1511, 1468}, 2},
{{1512, 1468}, 2}, {{1513, 1468}, 2}, {{1514, 1468}, 2}, {{1493, 1465}, 2}, {{1489, 1471}, 2}, {{1499, 1471}, 2},
{{1508, 1471}, 2}, {{119127, 119141}, 2}, {{119128, 119141}, 2}, {{119128, 119141, 119150}, 3},
{{119128, 119141, 119151}, 3}, {{119128, 119141, 119152}, 3}, {{119128, 119141, 119153}, 3},
{{119128, 119141, 119154}, 3}, {{119225, 119141}, 2}, {{119226, 119141}, 2}, {{119225, 119141, 119150}, 3},
{{119226, 119141, 119150}, 3}, {{119225, 119141, 119151}, 3}, {{119226, 119141, 119151}, 3}, {{20029}, 1},
{{20024}, 1}, {{20033}, 1}, {{131362}, 1}, {{20320}, 1}, {{20398}, 1}, {{20411}, 1}, {{20482}, 1}, {{20602}, 1},
{{20633}, 1}, {{20711}, 1}, {{20687}, 1}, {{13470}, 1}, {{132666}, 1}, {{20813}, 1}, {{20820}, 1}, {{20836}, 1},
{{20855}, 1}, {{132380}, 1}, {{13497}, 1}, {{20839}, 1}, {{20877}, 1}, {{132427}, 1}, {{20887}, 1}, {{20900}, 1},
{{20172}, 1}, {{20908}, 1}, {{20917}, 1}, {{168415}, 1}, {{20981}, 1}, {{20995}, 1}, {{13535}, 1}, {{21051}, 1},
{{21062}, 1}, {{21106}, 1}, {{21111}, 1}, {{13589}, 1}, {{21191}, 1}, {{21193}, 1}, {{21220}, 1}, {{21242}, 1},
{{21253}, 1}, {{21254}, 1}, {{21271}, 1}, {{21321}, 1}, {{21329}, 1}, {{21338}, 1}, {{21363}, 1}, {{21373}, 1},
{{21375}, 1}, {{21375}, 1}, {{21375}, 1}, {{133676}, 1}, {{28784}, 1}, {{21450}, 1}, {{21471}, 1}, {{133987}, 1},
{{21483}, 1}, {{21489}, 1}, {{21510}, 1}, {{21662}, 1}, {{21560}, 1}, {{21576}, 1}, {{21608}, 1}, {{21666}, 1},
{{21750}, 1}, {{21776}, 1}, {{21843}, 1}, {{21859}, 1}, {{21892}, 1}, {{21892}, 1}, {{21913}, 1}, {{21931}, 1},
{{21939}, 1}, {{21954}, 1}, {{22294}, 1}, {{22022}, 1}, {{22295}, 1}, {{22097}, 1}, {{22132}, 1}, {{20999}, 1},
{{22766}, 1}, {{22478}, 1}, {{22516}, 1}, {{22541}, 1}, {{22411}, 1}, {{22578}, 1}, {{22577}, 1}, {{22700}, 1},
{{136420}, 1}, {{22770}, 1}, {{22775}, 1}, {{22790}, 1}, {{22810}, 1}, {{22818}, 1}, {{22882}, 1}, {{136872}, 1},
{{136938}, 1}, {{23020}, 1}, {{23067}, 1}, {{23079}, 1}, {{23000}, 1}, {{23142}, 1}, {{14062}, 1}, {{14076}, 1},
{{23304}, 1}, {{23358}, 1}, {{23358}, 1}, {{137672}, 1}, {{23491}, 1}, {{23512}, 1}, {{23527}, 1}, {{23539}, 1},
{{138008}, 1}, {{23551}, 1}, {{23558}, 1}, {{24403}, 1}, {{23586}, 1}, {{14209}, 1}, {{23648}, 1}, {{23662}, 1},
{{23744}, 1}, {{23693}, 1}, {{138724}, 1}, {{23875}, 1}, {{138726}, 1}, {{23918}, 1}, {{23915}, 1}, {{23932}, 1},
{{24033}, 1}, {{24034}, 1}, {{14383}, 1}, {{24061}, 1}, {{24104}, 1}, {{24125}, 1}, {{24169}, 1}, {{14434}, 1},
{{139651}, 1}, {{14460}, 1}, {{24240}, 1}, {{24243}, 1}, {{24246}, 1}, {{24266}, 1}, {{172946}, 1}, {{24318}, 1},
{{140081}, 1}, {{140081}, 1}, {{33281}, 1}, {{24354}, 1}, {{24354}, 1}, {{14535}, 1}, {{144056}, 1}, {{156122}, 1},
{{24418}, 1}, {{24427}, 1}, {{14563}, 1}, {{24474}, 1}, {{24525}, 1}, {{24535}, 1}, {{24569}, 1}, {{24705}, 1},
{{14650}, 1}, {{14620}, 1}, {{24724}, 1}, {{141012}, 1}, {{24775}, 1}, {{24904}, 1}, {{24908}, 1}, {{24910}, 1},
{{24908}, 1}, {{24954}, 1}, {{24974}, 1}, {{25010}, 1}, {{24996}, 1}, {{25007}, 1}, {{25054}, 1}, {{25074}, 1},
{{25078}, 1}, {{25104}, 1}, {{25115}, 1}, {{25181}, 1}, {{25265}, 1}, {{25300}, 1}, {{25424}, 1}, {{142092}, 1},
{{25405}, 1}, {{25340}, 1}, {{25448}, 1}, {{25475}, 1}, {{25572}, 1}, {{142321}, 1}, {{25634}, 1}, {{25541}, 1},
{{25513}, 1}, {{14894}, 1}, {{25705}, 1}, {{25726}, 1}, {{25757}, 1}, {{25719}, 1}, {{14956}, 1}, {{25935}, 1},
{{25964}, 1}, {{143370}, 1}, {{26083}, 1}, {{26360}, 1}, {{26185}, 1}, {{15129}, 1}, {{26257}, 1}, {{15112}, 1},
{{15076}, 1}, {{20882}, 1}, {{20885}, 1}, {{26368}, 1}, {{26268}, 1}, {{32941}, 1}, {{17369}, 1}, {{26391}, 1},
{{26395}, 1}, {{26401}, 1}, {{26462}, 1}, {{26451}, 1}, {{144323}, 1}, {{15177}, 1}, {{26618}, 1}, {{26501}, 1},
{{26706}, 1}, {{26757}, 1}, {{144493}, 1}, {{26766}, 1}, {{26655}, 1}, {{26900}, 1}, {{15261}, 1}, {{26946}, 1},
{{27043}, 1}, {{27114}, 1}, {{27304}, 1}, {{145059}, 1}, {{27355}, 1}, {{15384}, 1}, {{27425}, 1}, {{145575}, 1},
{{27476}, 1}, {{15438}, 1}, {{27506}, 1}, {{27551}, 1}, {{27578}, 1}, {{27579}, 1}, {{146061}, 1}, {{138507}, 1},
{{146170}, 1}, {{27726}, 1}, {{146620}, 1}, {{27839}, 1}, {{27853}, 1}, {{27751}, 1}, {{27926}, 1}, {{27966}, 1},
{{28023}, 1}, {{27969}, 1}, {{28009}, 1}, {{28024}, 1}, {{28037}, 1}, {{146718}, 1}, {{27956}, 1}, {{28207}, 1},
{{28270}, 1}, {{15667}, 1}, {{28363}, 1}, {{28359}, 1}, {{147153}, 1}, {{28153}, 1}, {{28526}, 1}, {{147294}, 1},
{{147342}, 1}, {{28614}, 1}, {{28729}, 1}, {{28702}, 1}, {{28699}, 1}, {{15766}, 1}, {{28746}, 1}, {{28797}, 1},
{{28791}, 1}, {{28845}, 1}, {{132389}, 1}, {{28997}, 1}, {{148067}, 1}, {{29084}, 1}, {{148395}, 1}, {{29224}, 1},
{{29237}, 1}, {{29264}, 1}, {{149000}, 1}, {{29312}, 1}, {{29333}, 1}, {{149301}, 1}, {{149524}, 1}, {{29562}, 1},
{{29579}, 1}, {{16044}, 1}, {{29605}, 1}, {{16056}, 1}, {{16056}, 1}, {{29767}, 1}, {{29788}, 1}, {{29809}, 1},
{{29829}, 1}, {{29898}, 1}, {{16155}, 1}, {{29988}, 1}, {{150582}, 1}, {{30014}, 1}, {{150674}, 1}, {{30064}, 1},
{{139679}, 1}, {{30224}, 1}, {{151457}, 1}, {{151480}, 1}, {{151620}, 1}, {{16380}, 1}, {{16392}, 1}, {{30452}, 1},
{{151795}, 1}, {{151794}, 1}, {{151833}, 1}, {{151859}, 1}, {{30494}, 1}, {{30495}, 1}, {{30495}, 1}, {{30538}, 1},
{{16441}, 1}, {{30603}, 1}, {{16454}, 1}, {{16534}, 1}, {{152605}, 1}, {{30798}, 1}, {{30860}, 1}, {{30924}, 1},
{{16611}, 1}, {{153126}, 1}, {{31062}, 1}, {{153242}, 1}, {{153285}, 1}, {{31119}, 1}, {{31211}, 1}, {{16687}, 1},
{{31296}, 1}, {{31306}, 1}, {{31311}, 1}, {{153980}, 1}, {{154279}, 1}, {{154279}, 1}, {{31470}, 1}, {{16898}, 1},
{{154539}, 1}, {{31686}, 1}, {{31689}, 1}, {{16935}, 1}, {{154752}, 1}, {{31954}, 1}, {{17056}, 1}, {{31976}, 1},
{{31971}, 1}, {{32000}, 1}, {{155526}, 1}, {{32099}, 1}, {{17153}, 1}, {{32199}, 1}, {{32258}, 1}, {{32325}, 1},
{{17204}, 1}, {{156200}, 1}, {{156231}, 1}, {{17241}, 1}, {{156377}, 1}, {{32634}, 1}, {{156478}, 1}, {{32661}, 1},
{{32762}, 1}, {{32773}, 1}, {{156890}, 1}, {{156963}, 1}, {{32864}, 1}, {{157096}, 1}, {{32880}, 1}, {{144223}, 1},
{{17365}, 1}, {{32946}, 1}, {{33027}, 1}, {{17419}, 1}, {{33086}, 1}, {{23221}, 1}, {{157607}, 1}, {{157621}, 1},
{{144275}, 1}, {{144284}, 1}, {{33281}, 1}, {{33284}, 1}, {{36766}, 1}, {{17515}, 1}, {{33425}, 1}, {{33419}, 1},
{{33437}, 1}, {{21171}, 1}, {{33457}, 1}, {{33459}, 1}, {{33469}, 1}, {{33510}, 1}, {{158524}, 1}, {{33509}, 1},
{{33565}, 1}, {{33635}, 1}, {{33709}, 1}, {{33571}, 1}, {{33725}, 1}, {{33767}, 1}, {{33879}, 1}, {{33619}, 1},
{{33738}, 1}, {{33740}, 1}, {{33756}, 1}, {{158774}, 1}, {{159083}, 1}, {{158933}, 1}, {{17707}, 1}, {{34033}, 1},
{{34035}, 1}, {{34070}, 1}, {{160714}, 1}, {{34148}, 1}, {{159532}, 1}, {{17757}, 1}, {{17761}, 1}, {{159665}, 1},
{{159954}, 1}, {{17771}, 1}, {{34384}, 1}, {{34396}, 1}, {{34407}, 1}, {{34409}, 1}, {{34473}, 1}, {{34440}, 1},
{{34574}, 1}, {{34530}, 1}, {{34681}, 1}, {{34600}, 1}, {{34667}, 1}, {{34694}, 1}, {{17879}, 1}, {{34785}, 1},
{{34817}, 1}, {{17913}, 1}, {{34912}, 1}, {{34915}, 1}, {{161383}, 1}, {{35031}, 1}, {{35038}, 1}, {{17973}, 1},
{{35066}, 1}, {{13499}, 1}, {{161966}, 1}, {{162150}, 1}, {{18110}, 1}, {{18119}, 1}, {{35488}, 1}, {{35565}, 1},
{{35722}, 1}, {{35925}, 1}, {{162984}, 1}, {{36011}, 1}, {{36033}, 1}, {{36123}, 1}, {{36215}, 1}, {{163631}, 1},
{{133124}, 1}, {{36299}, 1}, {{36284}, 1}, {{36336}, 1}, {{133342}, 1}, {{36564}, 1}, {{36664}, 1}, {{165330}, 1},
{{165357}, 1}, {{37012}, 1}, {{37105}, 1}, {{37137}, 1}, {{165678}, 1}, {{37147}, 1}, {{37432}, 1}, {{37591}, 1},
{{37592}, 1}, {{37500}, 1}, {{37881}, 1}, {{37909}, 1}, {{166906}, 1}, {{38283}, 1}, {{18837}, 1}, {{38327}, 1},
{{167287}, 1}, {{18918}, 1}, {{38595}, 1}, {{23986}, 1}, {{38691}, 1}, {{168261}, 1}, {{168474}, 1}, {{19054}, 1},
{{19062}, 1}, {{38880}, 1}, {{168970}, 1}, {{19122}, 1}, {{169110}, 1}, {{38923}, 1}, {{38923}, 1}, {{38953}, 1},
{{169398}, 1}, {{39138}, 1}, {{19251}, 1}, {{39209}, 1}, {{39335}, 1}, {{39362}, 1}, {{39422}, 1}, {{19406}, 1},
{{170800}, 1}, {{39698}, 1}, {{40000}, 1}, {{40189}, 1}, {{19662}, 1}, {{19693}, 1}, {{40295}, 1}, {{172238}, 1},
{{19704}, 1}, {{172293}, 1}, {{172558}, 1}, {{172689}, 1}, {{40635}, 1}, {{19798}, 1}, {{40697}, 1}, {{40702}, 1},
{{40709}, 1}, {{40719}, 1}, {{40726}, 1}, {{40763}, 1}, {{173568}, 1}
};
KInt getCanonicalClass(KInt ch) {
int index = binarySearchRange(canonicalClassesKeys, ARRAY_SIZE(canonicalClassesKeys), ch);
if (canonicalClassesKeys[index] != ch) {
return 0;
}
return canonicalClassesValues[index];
}
const Decomposition* getDecomposition(KInt codePoint) {
int index = binarySearchRange(decompositionKeys, ARRAY_SIZE(decompositionKeys), codePoint);
if (decompositionKeys[index] != codePoint) {
return nullptr;
}
return &decompositionValues[index];
}
} // namespace
extern "C" {
KInt Kotlin_text_regex_getCanonicalClassInternal(KInt ch) {
return getCanonicalClass(ch);
}
KBoolean Kotlin_text_regex_hasSingleCodepointDecompositionInternal(KInt ch) {
int index = binarySearchRange(singleDecompositions, ARRAY_SIZE(singleDecompositions), ch);
return singleDecompositions[index] == ch;
}
OBJ_GETTER(Kotlin_text_regex_getDecompositionInternal, KInt ch) {
const Decomposition* decomposition = getDecomposition(ch);
if (decomposition == nullptr) {
return nullptr;
}
ArrayHeader* result = AllocArrayInstance(theIntArrayTypeInfo, decomposition->length, OBJ_RESULT)->array();
KInt* resultRaw = IntArrayAddressOfElementAt(result, 0);
for (int i = 0; i < decomposition->length; i++) {
*resultRaw++ = decomposition->array[i];
}
RETURN_OBJ(result->obj());
}
KInt Kotlin_text_regex_decomposeString(ArrayHeader* inputCodePoints, KInt inputLength, ArrayHeader* outputCodePoints) {
RuntimeAssert(inputCodePoints->type_info() == theIntArrayTypeInfo, "Must use an Int array");
RuntimeAssert(outputCodePoints->type_info() == theIntArrayTypeInfo, "Must use an Int array");
RuntimeAssert(inputLength >= 0, "Input length must be >= 0");
if (inputLength == 0) {
return 0;
}
int outputLength = 0;
const KInt* inputArray = IntArrayAddressOfElementAt(inputCodePoints, 0);
KInt* outputArray = IntArrayAddressOfElementAt(outputCodePoints, 0);
for (int i = 0; i < inputLength; i++) {
const Decomposition* decomposition = getDecomposition(inputArray[i]);
if (decomposition == nullptr) {
outputArray[outputLength++] = inputArray[i];
} else {
memcpy(outputArray + outputLength, decomposition->array, decomposition->length * sizeof(KInt));
outputLength+=decomposition->length;
}
}
return outputLength;
}
KInt Kotlin_text_regex_decomposeCodePoint(KInt codePoint, ArrayHeader* outputCodePoints, KInt fromIndex) {
RuntimeAssert(outputCodePoints->type_info() == theIntArrayTypeInfo, "Must be an Int array");
RuntimeAssert(fromIndex >= 0 && static_cast<uint32_t>(fromIndex) < outputCodePoints->count_, "Start index must be >= 0 and < array size");
KInt* rawResult = IntArrayAddressOfElementAt(outputCodePoints, fromIndex);
const Decomposition* decomposition = getDecomposition(codePoint);
if (decomposition == nullptr) {
*rawResult = codePoint;
return 1;
} else {
memcpy(rawResult, decomposition->array, decomposition->length * sizeof(KInt));
return decomposition->length;
}
}
} // extern "C"
@@ -0,0 +1,40 @@
/*
* 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.
*/
#include "ReturnSlot.h"
#ifdef KONAN_WASM
namespace {
THREAD_LOCAL_VARIABLE long long storage;
} // namespace
extern "C" {
RUNTIME_USED
KDouble ReturnSlot_getDouble() {
return *reinterpret_cast<KDouble*>(&::storage);
}
RUNTIME_USED
void ReturnSlot_setDouble(KInt upper, KInt lower) {
reinterpret_cast<KInt*>(&::storage)[0] = lower;
reinterpret_cast<KInt*>(&::storage)[1] = upper;
}
} // extern "C"
#endif // KONAN_WASM
@@ -0,0 +1,32 @@
/*
* 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.
*/
#include "Types.h"
#ifdef KONAN_WASM
#ifdef __cplusplus
extern "C" {
#endif
KDouble ReturnSlot_getDouble();
void ReturnSlot_setDouble(KInt upper, KInt lower);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // KONAN_WASM
@@ -0,0 +1,256 @@
/*
* 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.
*/
#include "Alloc.h"
#include "Atomic.h"
#include "Cleaner.h"
#include "Exceptions.h"
#include "KAssert.h"
#include "Memory.h"
#include "ObjCExportInit.h"
#include "Porting.h"
#include "Runtime.h"
#include "Worker.h"
typedef void (*Initializer)(int initialize, MemoryState* memory);
struct InitNode {
Initializer init;
InitNode* next;
};
namespace {
InitNode* initHeadNode = nullptr;
InitNode* initTailNode = nullptr;
enum class RuntimeStatus {
kUninitialized,
kRunning,
kDestroying,
};
struct RuntimeState {
MemoryState* memoryState;
Worker* worker;
RuntimeStatus status = RuntimeStatus::kUninitialized;
};
enum {
INIT_GLOBALS = 0,
INIT_THREAD_LOCAL_GLOBALS = 1,
DEINIT_THREAD_LOCAL_GLOBALS = 2,
DEINIT_GLOBALS = 3
};
void InitOrDeinitGlobalVariables(int initialize, MemoryState* memory) {
InitNode* currentNode = initHeadNode;
while (currentNode != nullptr) {
currentNode->init(initialize, memory);
currentNode = currentNode->next;
}
}
KBoolean g_checkLeaks = KonanNeedDebugInfo;
KBoolean g_checkLeakedCleaners = KonanNeedDebugInfo;
constexpr RuntimeState* kInvalidRuntime = nullptr;
THREAD_LOCAL_VARIABLE RuntimeState* runtimeState = kInvalidRuntime;
THREAD_LOCAL_VARIABLE int isMainThread = 0;
inline bool isValidRuntime() {
return ::runtimeState != kInvalidRuntime;
}
volatile int aliveRuntimesCount = 0;
RuntimeState* initRuntime() {
SetKonanTerminateHandler();
RuntimeState* result = konanConstructInstance<RuntimeState>();
if (!result) return kInvalidRuntime;
RuntimeCheck(!isValidRuntime(), "No active runtimes allowed");
::runtimeState = result;
result->memoryState = InitMemory();
result->worker = WorkerInit(true);
bool firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1;
// Keep global variables in state as well.
if (firstRuntime) {
isMainThread = 1;
konan::consoleInit();
#if KONAN_OBJC_INTEROP
Kotlin_ObjCExport_initialize();
#endif
InitOrDeinitGlobalVariables(INIT_GLOBALS, result->memoryState);
}
InitOrDeinitGlobalVariables(INIT_THREAD_LOCAL_GLOBALS, result->memoryState);
RuntimeAssert(result->status == RuntimeStatus::kUninitialized, "Runtime must still be in the uninitialized state");
result->status = RuntimeStatus::kRunning;
return result;
}
void deinitRuntime(RuntimeState* state) {
RuntimeAssert(state->status == RuntimeStatus::kRunning, "Runtime must be in the running state");
state->status = RuntimeStatus::kDestroying;
// This may be called after TLS is zeroed out, so ::memoryState in Memory cannot be trusted.
RestoreMemory(state->memoryState);
bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0;
InitOrDeinitGlobalVariables(DEINIT_THREAD_LOCAL_GLOBALS, state->memoryState);
if (lastRuntime)
InitOrDeinitGlobalVariables(DEINIT_GLOBALS, state->memoryState);
auto workerId = GetWorkerId(state->worker);
WorkerDeinit(state->worker);
DeinitMemory(state->memoryState);
konanDestructInstance(state);
WorkerDestroyThreadDataIfNeeded(workerId);
}
void Kotlin_deinitRuntimeCallback(void* argument) {
auto* state = reinterpret_cast<RuntimeState*>(argument);
deinitRuntime(state);
}
} // namespace
extern "C" {
void AppendToInitializersTail(InitNode *next) {
// TODO: use RuntimeState.
if (initHeadNode == nullptr) {
initHeadNode = next;
} else {
initTailNode->next = next;
}
initTailNode = next;
}
void Kotlin_initRuntimeIfNeeded() {
if (!isValidRuntime()) {
initRuntime();
// Register runtime deinit function at thread cleanup.
konan::onThreadExit(Kotlin_deinitRuntimeCallback, runtimeState);
}
}
void Kotlin_deinitRuntimeIfNeeded() {
if (isValidRuntime()) {
deinitRuntime(::runtimeState);
::runtimeState = kInvalidRuntime;
}
}
void CheckIsMainThread() {
if (!isMainThread)
ThrowIncorrectDereferenceException();
}
KInt Konan_Platform_canAccessUnaligned() {
#if KONAN_NO_UNALIGNED_ACCESS
return 0;
#else
return 1;
#endif
}
KInt Konan_Platform_isLittleEndian() {
#ifdef __BIG_ENDIAN__
return 0;
#else
return 1;
#endif
}
KInt Konan_Platform_getOsFamily() {
#if KONAN_MACOSX
return 1;
#elif KONAN_IOS
return 2;
#elif KONAN_LINUX
return 3;
#elif KONAN_WINDOWS
return 4;
#elif KONAN_ANDROID
return 5;
#elif KONAN_WASM
return 6;
#elif KONAN_TVOS
return 7;
#elif KONAN_WATCHOS
return 8;
#else
#warning "Unknown platform"
return 0;
#endif
}
KInt Konan_Platform_getCpuArchitecture() {
#if KONAN_ARM32
return 1;
#elif KONAN_ARM64
return 2;
#elif KONAN_X86
return 3;
#elif KONAN_X64
return 4;
#elif KONAN_MIPS32
return 5;
#elif KONAN_MIPSEL32
return 6;
#elif KONAN_WASM
return 7;
#else
#warning "Unknown CPU"
return 0;
#endif
}
KInt Konan_Platform_getMemoryModel() {
return IsStrictMemoryModel ? 0 : 1;
}
KBoolean Konan_Platform_isDebugBinary() {
return KonanNeedDebugInfo ? true : false;
}
void Kotlin_zeroOutTLSGlobals() {
if (runtimeState != nullptr && runtimeState->memoryState != nullptr)
InitOrDeinitGlobalVariables(DEINIT_THREAD_LOCAL_GLOBALS, runtimeState->memoryState);
}
bool Kotlin_memoryLeakCheckerEnabled() {
return g_checkLeaks;
}
KBoolean Konan_Platform_getMemoryLeakChecker() {
return g_checkLeaks;
}
void Konan_Platform_setMemoryLeakChecker(KBoolean value) {
g_checkLeaks = value;
}
bool Kotlin_cleanersLeakCheckerEnabled() {
return g_checkLeakedCleaners;
}
KBoolean Konan_Platform_getCleanersLeakChecker() {
return g_checkLeakedCleaners;
}
void Konan_Platform_setCleanersLeakChecker(KBoolean value) {
g_checkLeakedCleaners = value;
}
} // extern "C"
@@ -0,0 +1,45 @@
/*
* 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_RUNTIME_H
#define RUNTIME_RUNTIME_H
#include "Porting.h"
struct InitNode;
#ifdef __cplusplus
extern "C" {
#endif
void Kotlin_initRuntimeIfNeeded();
void Kotlin_deinitRuntimeIfNeeded();
// Appends given node to an initializer list.
void AppendToInitializersTail(struct InitNode*);
// Zero out all Kotlin thread local globals.
void Kotlin_zeroOutTLSGlobals();
bool Kotlin_memoryLeakCheckerEnabled();
bool Kotlin_cleanersLeakCheckerEnabled();
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_RUNTIME_H
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 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_SOURCEINFO_H
#define RUNTIME_SOURCEINFO_H
struct SourceInfo {
const char* fileName;
int lineNumber;
int column;
};
#ifdef __cplusplus
extern "C" {
#endif
struct SourceInfo Kotlin_getSourceInfo(void* addr);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // RUNTIME_SOURCEINFO_H
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2018 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.
*/
#include "KAssert.h"
#include "Porting.h"
#include "Common.h"
#if KONAN_LINUX || KONAN_WINDOWS
// This function replaces `__cxa_demangle` defined in GNU libstdc++
// by adding `--defsym` flag in `konan.properties`.
// This allows to avoid linking `__cxa_demangle` and its dependencies, thus reducing binary size.
RUNTIME_USED RUNTIME_WEAK extern "C" char* Konan_cxa_demangle(
const char* __mangled_name, char* __output_buffer,
size_t* __length, int* __status
) {
*__status = -2; // __mangled_name is not a valid name under the C++ ABI mangling rules.
return nullptr;
}
namespace std {
void __throw_length_error(const char* __s __attribute__((unused))) {
RuntimeAssert(false, __s);
}
} // namespace std
#endif // KONAN_LINUX || KONAN_WINDOWS
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include <memory>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "Types.h"
template <class F>
class ScopedStrictMockFunction {
public:
using Mock = testing::StrictMock<testing::MockFunction<F>>;
explicit ScopedStrictMockFunction(Mock** globalMockLocation) : globalMockLocation_(globalMockLocation) {
RuntimeCheck(globalMockLocation != nullptr, "ScopedStrictMockFunction needs non-null global mock location");
RuntimeCheck(*globalMockLocation == nullptr, "ScopedStrictMockFunction needs null global mock");
// TODO: Use make_unique when sysroots on Linux get updated.
mock_ = std::unique_ptr<Mock>(new Mock());
*globalMockLocation_ = mock_.get();
}
ScopedStrictMockFunction(const ScopedStrictMockFunction&) = delete;
ScopedStrictMockFunction& operator=(const ScopedStrictMockFunction&) = delete;
ScopedStrictMockFunction(ScopedStrictMockFunction&& rhs) : globalMockLocation_(rhs.globalMockLocation_), mock_(std::move(rhs.mock_)) {
rhs.globalMockLocation_ = nullptr;
}
ScopedStrictMockFunction& operator=(ScopedStrictMockFunction&& rhs) {
ScopedStrictMockFunction tmp(std::move(rhs));
swap(tmp);
return *this;
}
~ScopedStrictMockFunction() {
if (!globalMockLocation_) return;
RuntimeCheck(*globalMockLocation_ == mock_.get(), "unexpected global mock location");
testing::Mock::VerifyAndClear(mock_.get());
mock_.reset();
*globalMockLocation_ = nullptr;
}
void swap(ScopedStrictMockFunction& other) {
std::swap(globalMockLocation_, other.globalMockLocation_);
std::swap(mock_, other.mock_);
}
Mock& get() { return *mock_; }
Mock& operator*() { return *mock_; }
private:
// Can be null if moved-out of.
Mock** globalMockLocation_;
std::unique_ptr<Mock> mock_;
};
ScopedStrictMockFunction<KInt()> ScopedCreateCleanerWorkerMock();
ScopedStrictMockFunction<void(KInt, bool)> ScopedShutdownCleanerWorkerMock();
@@ -0,0 +1,35 @@
/*
* 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.
*/
#include "Natives.h"
#include "Porting.h"
#include "Types.h"
extern "C" {
KLong Kotlin_system_getTimeMillis() {
return konan::getTimeMillis();
}
KLong Kotlin_system_getTimeNanos() {
return konan::getTimeNanos();
}
KLong Kotlin_system_getTimeMicros() {
return konan::getTimeMicros();
}
} // extern "C"
@@ -0,0 +1,122 @@
/*
* 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.
*/
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "KAssert.h"
#include "Exceptions.h"
#include "Memory.h"
#include "Natives.h"
#include "KString.h"
#include "Porting.h"
#include "Types.h"
namespace {
char int_to_digit(uint32_t value) {
if (value < 10) {
return '0' + value;
} else {
return 'a' + (value - 10);
}
}
// Radix is checked on the Kotlin side.
template <typename T> OBJ_GETTER(Kotlin_toStringRadix, T value, KInt radix) {
if (value == 0) {
RETURN_RESULT_OF(CreateStringFromCString, "0");
}
// In the worst case, we convert to binary, with sign.
char cstring[sizeof(T) * CHAR_BIT + 2];
bool negative = (value < 0);
if (!negative) {
value = -value;
}
int32_t length = 0;
while (value < 0) {
cstring[length++] = int_to_digit(-(value % radix));
value /= radix;
}
if (negative) {
cstring[length++] = '-';
}
for (int i = 0, j = length - 1; i < j; i++, j--) {
char tmp = cstring[i];
cstring[i] = cstring[j];
cstring[j] = tmp;
}
cstring[length] = '\0';
RETURN_RESULT_OF(CreateStringFromCString, cstring);
}
} // namespace
extern "C" {
OBJ_GETTER(Kotlin_Byte_toString, KByte value) {
char cstring[8];
konan::snprintf(cstring, sizeof(cstring), "%d", value);
RETURN_RESULT_OF(CreateStringFromCString, cstring);
}
OBJ_GETTER(Kotlin_Char_toString, KChar value) {
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, 1, OBJ_RESULT)->array();
*CharArrayAddressOfElementAt(result, 0) = value;
RETURN_OBJ(result->obj());
}
OBJ_GETTER(Kotlin_Short_toString, KShort value) {
char cstring[8];
konan::snprintf(cstring, sizeof(cstring), "%d", value);
RETURN_RESULT_OF(CreateStringFromCString, cstring);
}
OBJ_GETTER(Kotlin_Int_toString, KInt value) {
char cstring[16];
konan::snprintf(cstring, sizeof(cstring), "%d", value);
RETURN_RESULT_OF(CreateStringFromCString, cstring);
}
OBJ_GETTER(Kotlin_Int_toStringRadix, KInt value, KInt radix) {
RETURN_RESULT_OF(Kotlin_toStringRadix<KInt>, value, radix)
}
OBJ_GETTER(Kotlin_Long_toString, KLong value) {
char cstring[32];
konan::snprintf(cstring, sizeof(cstring), "%lld", static_cast<long long>(value));
RETURN_RESULT_OF(CreateStringFromCString, cstring);
}
OBJ_GETTER(Kotlin_Long_toStringRadix, KLong value, KInt radix) {
RETURN_RESULT_OF(Kotlin_toStringRadix<KLong>, value, radix)
}
OBJ_GETTER(Kotlin_DurationValue_formatToExactDecimals, KDouble value, KInt decimals) {
char cstring[32];
konan::snprintf(cstring, sizeof(cstring), "%.*f", decimals, value);
RETURN_RESULT_OF(CreateStringFromCString, cstring)
}
OBJ_GETTER(Kotlin_DurationValue_formatScientificImpl, KDouble value) {
char cstring[16];
konan::snprintf(cstring, sizeof(cstring), "%.2e", value);
RETURN_RESULT_OF(CreateStringFromCString, cstring)
}
} // extern "C"
@@ -0,0 +1,79 @@
/*
* 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.
*/
#include "KAssert.h"
#include "TypeInfo.h"
// If one shall use binary search when looking up methods and fields.
// TODO: maybe select strategy basing on number of elements.
#define USE_BINARY_SEARCH 1
extern "C" {
#if USE_BINARY_SEARCH
void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) {
int bottom = 0;
int top = info->openMethodsCount_ - 1;
while (bottom <= top) {
int middle = (bottom + top) / 2;
if (info->openMethods_[middle].nameSignature_ < nameSignature)
bottom = middle + 1;
else if (info->openMethods_[middle].nameSignature_ == nameSignature)
return info->openMethods_[middle].methodEntryPoint_;
else
top = middle - 1;
}
RuntimeAssert(false, "Unknown open method");
return nullptr;
}
#else
void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) {
for (int i = 0; i < info->openMethodsCount_; ++i) {
if (info->openMethods_[i].nameSignature_ == nameSignature) {
return info->openMethods_[i].methodEntryPoint_;
}
}
RuntimeAssert(false, "Unknown open method");
return nullptr;
}
#endif
// Seeks for the specified id. In case of failure returns a valid pointer to some record, never returns nullptr.
// It is the caller's responsibility to check if the search has succeeded or not.
InterfaceTableRecord const* LookupInterfaceTableRecord(InterfaceTableRecord const* interfaceTable,
int interfaceTableSize, ClassId interfaceId) {
if (interfaceTableSize <= 8) {
// Linear search.
int i;
for (i = 0; i < interfaceTableSize - 1 && interfaceTable[i].id < interfaceId; ++i);
return interfaceTable + i;
}
int l = 0, r = interfaceTableSize - 1;
while (l < r) {
int m = (l + r) / 2;
if (interfaceTable[m].id < interfaceId)
l = m + 1;
else r = m;
}
return interfaceTable + l;
}
}
@@ -0,0 +1,181 @@
/*
* 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_TYPEINFO_H
#define RUNTIME_TYPEINFO_H
#include <cstdint>
#include "Common.h"
#include "Names.h"
#if KONAN_TYPE_INFO_HAS_WRITABLE_PART
struct WritableTypeInfo;
#endif
struct ObjHeader;
struct AssociatedObjectTableRecord;
// An element of sorted by hash in-place array representing methods.
// For systems where introspection is not needed - only open methods are in
// this table.
struct MethodTableRecord {
MethodNameHash nameSignature_;
void* methodEntryPoint_;
};
// Type for runtime representation of Konan object.
// Keep in sync with runtimeTypeMap in RTTIGenerator.
enum Konan_RuntimeType {
RT_INVALID = 0,
RT_OBJECT = 1,
RT_INT8 = 2,
RT_INT16 = 3,
RT_INT32 = 4,
RT_INT64 = 5,
RT_FLOAT32 = 6,
RT_FLOAT64 = 7,
RT_NATIVE_PTR = 8,
RT_BOOLEAN = 9,
RT_VECTOR128 = 10
};
// Flags per type.
// Keep in sync with constants in RTTIGenerator.
enum Konan_TypeFlags {
TF_IMMUTABLE = 1 << 0,
TF_ACYCLIC = 1 << 1,
TF_INTERFACE = 1 << 2,
TF_OBJC_DYNAMIC = 1 << 3,
TF_LEAK_DETECTOR_CANDIDATE = 1 << 4,
TF_SUSPEND_FUNCTION = 1 << 5,
TF_HAS_FINALIZER = 1 << 6,
};
// Flags per object instance.
enum Konan_MetaFlags {
// If freeze attempt happens on such an object - throw an exception.
MF_NEVER_FROZEN = 1 << 0,
};
// Extended information about a type.
struct ExtendedTypeInfo {
// Number of fields (negated Konan_RuntimeType for array types).
int32_t fieldsCount_;
// Offsets of all fields.
const int32_t* fieldOffsets_;
// Types of all fields.
const uint8_t* fieldTypes_;
// Names of all fields.
const char** fieldNames_;
// Number of supported debug operations.
int32_t debugOperationsCount_;
// Table of supported debug operations functions.
void** debugOperations_;
};
typedef void const* VTableElement;
typedef int32_t ClassId;
const ClassId kInvalidInterfaceId = 0;
struct InterfaceTableRecord {
ClassId id;
uint32_t vtableSize;
VTableElement const* vtable;
};
// This struct represents runtime type information and by itself is the compile time
// constant.
struct TypeInfo {
// Reference to self, to allow simple obtaining TypeInfo via meta-object.
const TypeInfo* typeInfo_;
// Extended RTTI, to retain cross-version debuggability, since ABI version 5 shall always be at the second position.
const ExtendedTypeInfo* extendedInfo_;
// Unused field.
uint32_t unused_;
// Negative value marks array class/string, and it is negated element size.
int32_t instanceSize_;
// Must be pointer to Any for array classes, and null for Any.
const TypeInfo* superType_;
// All object reference fields inside this object.
const int32_t* objOffsets_;
// Count of object reference fields inside this object.
// 1 for kotlin.Array to mark it as non-leaf.
int32_t objOffsetsCount_;
const TypeInfo* const* implementedInterfaces_;
int32_t implementedInterfacesCount_;
// Null for abstract classes and interfaces.
const MethodTableRecord* openMethods_;
uint32_t openMethodsCount_;
int32_t interfaceTableSize_;
InterfaceTableRecord const* interfaceTable_;
// String for the fully qualified dot-separated name of the package containing class,
// or `null` if the class is local or anonymous.
ObjHeader* packageName_;
// String for the qualified class name relative to the containing package
// (e.g. TopLevel.Nested1.Nested2), or simple class name if it is local,
// or `null` if the class is anonymous.
ObjHeader* relativeName_;
// Various flags.
int32_t flags_;
// Class id built with the whole class hierarchy taken into account. The details are in ClassLayoutBuilder.
ClassId classId_;
#if KONAN_TYPE_INFO_HAS_WRITABLE_PART
WritableTypeInfo* writableInfo_;
#endif
// Null-terminated array.
const AssociatedObjectTableRecord* associatedObjects;
// vtable starts just after declared contents of the TypeInfo:
// void* const vtable_[];
#ifdef __cplusplus
inline VTableElement const* vtable() const {
return reinterpret_cast<VTableElement const*>(this + 1);
}
inline VTableElement* vtable() {
return reinterpret_cast<VTableElement*>(this + 1);
}
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
// Find open method by its hash. Other methods are resolved in compile-time.
// Note, that we use attribute const, which assumes function doesn't
// dereference global memory, while this function does. However, it seems
// to be safe, as actual result of this computation depends only on 'type_info'
// and 'hash' numeric values and doesn't really depends on global memory state
// (as TypeInfo is compile time constant and type info pointers are stable).
void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) RUNTIME_CONST;
InterfaceTableRecord const* LookupInterfaceTableRecord(InterfaceTableRecord const* interfaceTable,
int interfaceTableSize, ClassId interfaceId) RUNTIME_CONST;
#ifdef __cplusplus
} // extern "C"
#endif
#endif // RUNTIME_TYPEINFO_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.
*/
#include "Types.h"
#include "Exceptions.h"
extern "C" {
KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) {
// We assume null check is handled by caller.
RuntimeAssert(obj != nullptr, "must not be null");
const TypeInfo* obj_type_info = obj->type_info();
// If it is an interface - check in list of implemented interfaces.
if ((type_info->flags_ & TF_INTERFACE) != 0) {
for (int i = 0; i < obj_type_info->implementedInterfacesCount_; ++i) {
if (obj_type_info->implementedInterfaces_[i] == type_info) {
return 1;
}
}
return 0;
}
while (obj_type_info != nullptr && obj_type_info != type_info) {
obj_type_info = obj_type_info->superType_;
}
return obj_type_info != nullptr;
}
KBoolean IsInstanceOfClassFast(const ObjHeader* obj, int32_t lo, int32_t hi) {
// We assume null check is handled by caller.
RuntimeAssert(obj != nullptr, "must not be null");
const TypeInfo* obj_type_info = obj->type_info();
// Super type's interval should contain our interval.
return obj_type_info->classId_ >= lo && obj_type_info->classId_ <= hi;
}
KBoolean IsArray(KConstRef obj) {
RuntimeAssert(obj != nullptr, "Object must not be null");
return obj->type_info()->instanceSize_ < 0;
}
KBoolean Kotlin_TypeInfo_isInstance(KConstRef obj, KNativePtr typeInfo) {
return IsInstance(obj, reinterpret_cast<const TypeInfo*>(typeInfo));
}
OBJ_GETTER(Kotlin_TypeInfo_getPackageName, KNativePtr typeInfo) {
RETURN_OBJ(reinterpret_cast<const TypeInfo*>(typeInfo)->packageName_);
}
OBJ_GETTER(Kotlin_TypeInfo_getRelativeName, KNativePtr typeInfo) {
RETURN_OBJ(reinterpret_cast<const TypeInfo*>(typeInfo)->relativeName_);
}
struct AssociatedObjectTableRecord {
const TypeInfo* key;
OBJ_GETTER0((*getAssociatedObjectInstance));
};
OBJ_GETTER(Kotlin_TypeInfo_findAssociatedObject, KNativePtr typeInfo, KNativePtr key) {
const AssociatedObjectTableRecord* associatedObjects = reinterpret_cast<const TypeInfo*>(typeInfo)->associatedObjects;
if (associatedObjects == nullptr) {
RETURN_OBJ(nullptr);
}
for (int index = 0; associatedObjects[index].key != nullptr; ++index) {
if (associatedObjects[index].key == key) {
RETURN_RESULT_OF0(associatedObjects[index].getAssociatedObjectInstance);
}
}
RETURN_OBJ(nullptr);
}
bool IsSubInterface(const TypeInfo* thiz, const TypeInfo* other) {
for (int i = 0; i < thiz->implementedInterfacesCount_; ++i) {
if (thiz->implementedInterfaces_[i] == other) {
return true;
}
}
return false;
}
KVector4f Kotlin_Vector4f_of(KFloat f0, KFloat f1, KFloat f2, KFloat f3) {
return {f0, f1, f2, f3};
}
/*
* In the current design all simd types are mapped internally to floating type, e.g. <4 x float>.
* However, some platforms (ex. arm32) have different calling convention for <4 x float> and <4 x i32>.
* To avoid illegal bitcast from/to function types the following function
* return type MUST be <4 x float> and explicit type cast is done on the variable type.
*/
KVector4f Kotlin_Vector4i32_of(KInt f0, KInt f1, KInt f2, KInt f3) {
KInt __attribute__ ((__vector_size__(16))) v4i = {f0, f1, f2, f3};
return (KVector4f)v4i;
}
} // extern "C"
+121
View File
@@ -0,0 +1,121 @@
/*
* 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_TYPES_H
#define RUNTIME_TYPES_H
#include <stdlib.h>
#if (KONAN_WASM || KONAN_ZEPHYR) && !defined(assert)
// assert() is needed by STLport.
#define assert(cond) if (!(cond)) abort()
#endif
#include <deque>
#include <list>
#include <map>
#include <string>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "Alloc.h"
#include "Common.h"
#include "Memory.h"
#include "TypeInfo.h"
// Note that almost all types are signed.
typedef bool KBoolean;
typedef int8_t KByte;
typedef uint16_t KChar;
typedef int16_t KShort;
typedef int32_t KInt;
typedef int64_t KLong;
typedef uint8_t KUByte;
typedef uint16_t KUShort;
typedef uint32_t KUInt;
typedef uint64_t KULong;
typedef float KFloat;
typedef double KDouble;
typedef void* KNativePtr;
typedef KFloat __attribute__ ((__vector_size__ (16))) KVector4f;
typedef const void* KConstNativePtr;
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, class Compare = std::less<Value>>
using KStdOrderedSet = std::set<Value, Compare, KonanAllocator<Value>>;
template<class Key, class Value, class Compare = std::less<Key>>
using KStdOrderedMap = std::map<Key, Value, Compare, KonanAllocator<std::pair<const Key, Value>>>;
template<class Value>
using KStdVector = std::vector<Value, KonanAllocator<Value>>;
template<class Value>
using KStdList = std::list<Value, KonanAllocator<Value>>;
#ifdef __cplusplus
extern "C" {
#endif
extern const TypeInfo* theAnyTypeInfo;
extern const TypeInfo* theArrayTypeInfo;
extern const TypeInfo* theBooleanArrayTypeInfo;
extern const TypeInfo* theByteArrayTypeInfo;
extern const TypeInfo* theCharArrayTypeInfo;
extern const TypeInfo* theDoubleArrayTypeInfo;
extern const TypeInfo* theForeignObjCObjectTypeInfo;
extern const TypeInfo* theIntArrayTypeInfo;
extern const TypeInfo* theLongArrayTypeInfo;
extern const TypeInfo* theNativePtrArrayTypeInfo;
extern const TypeInfo* theFloatArrayTypeInfo;
extern const TypeInfo* theForeignObjCObjectTypeInfo;
extern const TypeInfo* theFreezableAtomicReferenceTypeInfo;
extern const TypeInfo* theObjCObjectWrapperTypeInfo;
extern const TypeInfo* theOpaqueFunctionTypeInfo;
extern const TypeInfo* theShortArrayTypeInfo;
extern const TypeInfo* theStringTypeInfo;
extern const TypeInfo* theThrowableTypeInfo;
extern const TypeInfo* theUnitTypeInfo;
extern const TypeInfo* theWorkerBoundReferenceTypeInfo;
extern const TypeInfo* theCleanerImplTypeInfo;
KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE;
KBoolean IsInstanceOfClassFast(const ObjHeader* obj, int32_t lo, int32_t hi) RUNTIME_PURE;
void CheckCast(const ObjHeader* obj, const TypeInfo* type_info);
KBoolean IsArray(KConstRef obj) RUNTIME_PURE;
bool IsSubInterface(const TypeInfo* thiz, const TypeInfo* other) RUNTIME_PURE;
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_TYPES_H
@@ -0,0 +1,55 @@
/*
* 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.
*/
#include <cstdint>
#include "KAssert.h"
class SimpleMutex {
private:
int32_t atomicInt = 0;
public:
void lock() {
while (!__sync_bool_compare_and_swap(&atomicInt, 0, 1)) {
// TODO: yield.
}
}
void unlock() {
if (!__sync_bool_compare_and_swap(&atomicInt, 1, 0)) {
RuntimeAssert(false, "Unable to unlock");
}
}
};
// TODO: use std::lock_guard instead?
template <class Mutex>
class LockGuard {
public:
explicit LockGuard(Mutex& mutex_) : mutex(mutex_) {
mutex.lock();
}
~LockGuard() {
mutex.unlock();
}
private:
Mutex& mutex;
LockGuard(const LockGuard&) = delete;
LockGuard& operator=(const LockGuard&) = delete;
};
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright 2010-2018 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.
*/
#include "Weak.h"
#include "Memory.h"
#include "Types.h"
namespace {
// TODO: an ugly hack with fixed layout.
struct WeakReferenceCounter {
ObjHeader header;
KRef referred;
KInt lock;
KInt cookie;
};
inline WeakReferenceCounter* asWeakReferenceCounter(ObjHeader* obj) {
return reinterpret_cast<WeakReferenceCounter*>(obj);
}
#if !KONAN_NO_THREADS
inline void lock(int32_t* address) {
RuntimeAssert(*address == 0 || *address == 1, "Incorrect lock state");
while (__sync_val_compare_and_swap(address, 0, 1) == 1);
}
inline void unlock(int32_t* address) {
int old = __sync_val_compare_and_swap(address, 1, 0);
RuntimeAssert(old == 1, "Incorrect lock state");
}
#endif
} // namespace
extern "C" {
OBJ_GETTER(makeWeakReferenceCounter, void*);
OBJ_GETTER(makeObjCWeakReferenceImpl, void*);
OBJ_GETTER(makePermanentWeakReferenceImpl, ObjHeader*);
// See Weak.kt for implementation details.
// Retrieve link on the counter object.
OBJ_GETTER(Konan_getWeakReferenceImpl, ObjHeader* referred) {
if (referred->permanent()) {
RETURN_RESULT_OF(makePermanentWeakReferenceImpl, referred);
}
#if KONAN_OBJC_INTEROP
if (IsInstance(referred, theObjCObjectWrapperTypeInfo)) {
RETURN_RESULT_OF(makeObjCWeakReferenceImpl, referred->GetAssociatedObject());
}
#endif // KONAN_OBJC_INTEROP
ObjHeader** weakCounterLocation = referred->GetWeakCounterLocation();
if (*weakCounterLocation == nullptr) {
ObjHolder counterHolder;
// Cast unneeded, just to emphasize we store an object reference as void*.
ObjHeader* counter = makeWeakReferenceCounter(reinterpret_cast<void*>(referred), counterHolder.slot());
UpdateHeapRefIfNull(weakCounterLocation, counter);
}
RETURN_OBJ(*weakCounterLocation);
}
// Materialize a weak reference to either null or the real reference.
OBJ_GETTER(Konan_WeakReferenceCounter_get, ObjHeader* counter) {
ObjHeader** referredAddress = &asWeakReferenceCounter(counter)->referred;
#if KONAN_NO_THREADS
RETURN_OBJ(*referredAddress);
#else
auto* weakCounter = asWeakReferenceCounter(counter);
RETURN_RESULT_OF(ReadHeapRefLocked, referredAddress, &weakCounter->lock, &weakCounter->cookie);
#endif
}
void WeakReferenceCounterClear(ObjHeader* counter) {
ObjHeader** referredAddress = &asWeakReferenceCounter(counter)->referred;
// Note, that we don't do UpdateRef here, as reference is weak.
#if KONAN_NO_THREADS
*referredAddress = nullptr;
#else
int32_t* lockAddress = &asWeakReferenceCounter(counter)->lock;
// Spinlock.
lock(lockAddress);
*referredAddress = nullptr;
unlock(lockAddress);
#endif
}
} // extern "C"
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_WEAK_H
#define RUNTIME_WEAK_H
#include "Memory.h"
extern "C" {
// Atomically clears counter object reference.
void WeakReferenceCounterClear(ObjHeader* counter);
} // extern "C"
#endif // RUNTIME_WEAK_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
#ifndef RUNTIME_WORKER_H
#define RUNTIME_WORKER_H
#include "Common.h"
#include "Types.h"
class Worker;
KInt GetWorkerId(Worker* worker);
Worker* WorkerInit(KBoolean errorReporting);
void WorkerDeinit(Worker* worker);
// Clean up all associated thread state, if this was a native worker.
void WorkerDestroyThreadDataIfNeeded(KInt id);
// Wait until all terminating native workers finish termination. Expected to be called at most once.
void WaitNativeWorkersTermination();
// Wait until terminating native worker `id` finishes termination. Expected to be called at most once for each worker.
void WaitNativeWorkerTermination(KInt id);
// Schedule the job without the result.
bool WorkerSchedule(KInt id, KNativePtr jobStablePtr);
#endif // RUNTIME_WORKER_H
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#include "WorkerBoundReference.h"
#include "Alloc.h"
#include "Memory.h"
#include "MemorySharedRefs.hpp"
namespace {
struct WorkerBoundReference {
ObjHeader header;
KRefSharedHolder* holder;
};
WorkerBoundReference* asWorkerBoundReference(KRef thiz) {
return reinterpret_cast<WorkerBoundReference*>(thiz);
}
} // namespace
RUNTIME_NOTHROW void DisposeWorkerBoundReference(KRef thiz) {
// DisposeSharedRef is only called when all references to thiz are gone.
// Can be null if WorkerBoundReference wasn't frozen.
if (auto* holder = asWorkerBoundReference(thiz)->holder) {
holder->dispose();
konanDestructInstance(holder);
}
}
// Defined in WorkerBoundReference.kt
extern "C" void Kotlin_WorkerBoundReference_freezeHook(KRef thiz);
RUNTIME_NOTHROW void WorkerBoundReferenceFreezeHook(KRef thiz) {
Kotlin_WorkerBoundReference_freezeHook(thiz);
}
extern "C" {
KNativePtr Kotlin_WorkerBoundReference_create(KRef value) {
auto* holder = konanConstructInstance<KRefSharedHolder>();
holder->init(value);
return holder;
}
OBJ_GETTER(Kotlin_WorkerBoundReference_deref, KNativePtr holder) {
RETURN_OBJ(reinterpret_cast<KRefSharedHolder*>(holder)->ref<ErrorPolicy::kDefaultValue>());
}
OBJ_GETTER(Kotlin_WorkerBoundReference_describe, KNativePtr holder) {
RETURN_RESULT_OF0(reinterpret_cast<KRefSharedHolder*>(holder)->describe);
}
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
#ifndef RUNTIME_SHAREDREF_H
#define RUNTIME_SHAREDREF_H
#include "Common.h"
#include "Types.h"
RUNTIME_NOTHROW void DisposeWorkerBoundReference(KRef thiz);
RUNTIME_NOTHROW void WorkerBoundReferenceFreezeHook(KRef thiz);
#endif // RUNTIME_SHAREDREF_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,904 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#include <string.h>
#include "cbigint.h"
#if defined(LINUX) || defined(FREEBSD) || defined(ZOS) || defined(MACOSX) || defined(AIX)
#define USE_LL
#endif
#ifdef HY_LITTLE_ENDIAN
#define at(i) (i)
#else
#define at(i) ((i)^1)
/* the sequence for halfAt is -1, 2, 1, 4, 3, 6, 5, 8... */
/* and it should correspond to 0, 1, 2, 3, 4, 5, 6, 7... */
#define halfAt(i) (-((-(i)) ^ 1))
#endif
#define HIGH_IN_U64(u64) ((u64) >> 32)
#if defined(USE_LL)
#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFFLL)
#else
#if defined(USE_L)
#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFFL)
#else
#define LOW_IN_U64(u64) ((u64) & 0x00000000FFFFFFFF)
#endif /* USE_L */
#endif /* USE_LL */
#if defined(USE_LL)
#define TEN_E1 (0xALL)
#define TEN_E2 (0x64LL)
#define TEN_E3 (0x3E8LL)
#define TEN_E4 (0x2710LL)
#define TEN_E5 (0x186A0LL)
#define TEN_E6 (0xF4240LL)
#define TEN_E7 (0x989680LL)
#define TEN_E8 (0x5F5E100LL)
#define TEN_E9 (0x3B9ACA00LL)
#define TEN_E19 (0x8AC7230489E80000LL)
#else
#if defined(USE_L)
#define TEN_E1 (0xAL)
#define TEN_E2 (0x64L)
#define TEN_E3 (0x3E8L)
#define TEN_E4 (0x2710L)
#define TEN_E5 (0x186A0L)
#define TEN_E6 (0xF4240L)
#define TEN_E7 (0x989680L)
#define TEN_E8 (0x5F5E100L)
#define TEN_E9 (0x3B9ACA00L)
#define TEN_E19 (0x8AC7230489E80000L)
#else
#define TEN_E1 (0xA)
#define TEN_E2 (0x64)
#define TEN_E3 (0x3E8)
#define TEN_E4 (0x2710)
#define TEN_E5 (0x186A0)
#define TEN_E6 (0xF4240)
#define TEN_E7 (0x989680)
#define TEN_E8 (0x5F5E100)
#define TEN_E9 (0x3B9ACA00)
#define TEN_E19 (0x8AC7230489E80000)
#endif /* USE_L */
#endif /* USE_LL */
#define TIMES_TEN(x) (((x) << 3) + ((x) << 1))
#define bitSection(x, mask, shift) (((x) & (mask)) >> (shift))
#define DOUBLE_TO_LONGBITS(dbl) (*((U_64 *)(&dbl)))
#define FLOAT_TO_INTBITS(flt) (*((U_32 *)(&flt)))
#define CREATE_DOUBLE_BITS(normalizedM, e) (((normalizedM) & MANTISSA_MASK) | (((U_64)((e) + E_OFFSET)) << 52))
#if defined(USE_LL)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
#define EXPONENT_MASK (0x7FF0000000000000LL)
#define NORMAL_MASK (0x0010000000000000LL)
#define SIGN_MASK (0x8000000000000000LL)
#else
#if defined(USE_L)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
#define EXPONENT_MASK (0x7FF0000000000000L)
#define NORMAL_MASK (0x0010000000000000L)
#define SIGN_MASK (0x8000000000000000L)
#else
#define MANTISSA_MASK (0x000FFFFFFFFFFFFF)
#define EXPONENT_MASK (0x7FF0000000000000)
#define NORMAL_MASK (0x0010000000000000)
#define SIGN_MASK (0x8000000000000000)
#endif /* USE_L */
#endif /* USE_LL */
#define E_OFFSET (1075)
#define FLOAT_MANTISSA_MASK (0x007FFFFF)
#define FLOAT_EXPONENT_MASK (0x7F800000)
#define FLOAT_NORMAL_MASK (0x00800000)
#define FLOAT_E_OFFSET (150)
IDATA
simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2)
{
/* assumes length > 0 */
IDATA index = 1;
*arg1 += arg2;
if (arg2 <= *arg1)
return 0;
else if (length == 1)
return 1;
while (++arg1[index] == 0 && ++index < length);
return (IDATA) index == length;
}
IDATA
addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
{
/* addition is limited by length of arg1 as it this function is
* storing the result in arg1 */
/* fix for cc (GCC) 3.2 20020903 (Red Hat Linux 8.0 3.2-7): code generated does not
* do the temp1 + temp2 + carry addition correct. carry is 64 bit because gcc has
* subtle issues when you mix 64 / 32 bit maths. */
U_64 temp1, temp2, temp3; /* temporary variables to help the SH-4, and gcc */
U_64 carry;
IDATA index;
if (length1 == 0 || length2 == 0)
{
return 0;
}
else if (length1 < length2)
{
length2 = length1;
}
carry = 0;
index = 0;
do
{
temp1 = arg1[index];
temp2 = arg2[index];
temp3 = temp1 + temp2;
arg1[index] = temp3 + carry;
if (arg2[index] < arg1[index])
carry = 0;
else if (arg2[index] != arg1[index])
carry = 1;
}
while (++index < length2);
if (!carry)
return 0;
else if (index == length1)
return 1;
while (++arg1[index] == 0 && ++index < length1);
return (IDATA) index == length1;
}
void
subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
{
/* assumes arg1 > arg2 */
IDATA index;
for (index = 0; index < length1; ++index)
arg1[index] = ~arg1[index];
simpleAddHighPrecision (arg1, length1, 1);
while (length2 > 0 && arg2[length2 - 1] == 0)
--length2;
addHighPrecision (arg1, length1, arg2, length2);
for (index = 0; index < length1; ++index)
arg1[index] = ~arg1[index];
simpleAddHighPrecision (arg1, length1, 1);
}
U_32
simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2)
{
/* assumes arg2 only holds 32 bits of information */
U_64 product;
IDATA index;
index = 0;
product = 0;
do
{
product =
HIGH_IN_U64 (product) + arg2 * LOW_U32_FROM_PTR (arg1 + index);
LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product);
product =
HIGH_IN_U64 (product) + arg2 * HIGH_U32_FROM_PTR (arg1 + index);
HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product);
}
while (++index < length);
return HIGH_U32_FROM_VAR (product);
}
void
simpleMultiplyAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2,
U_32 * result)
{
/* Assumes result can hold the product and arg2 only holds 32 bits
of information */
U_64 product;
IDATA index, resultIndex;
index = resultIndex = 0;
product = 0;
do
{
product =
HIGH_IN_U64 (product) + result[at (resultIndex)] +
arg2 * LOW_U32_FROM_PTR (arg1 + index);
result[at (resultIndex)] = LOW_U32_FROM_VAR (product);
++resultIndex;
product =
HIGH_IN_U64 (product) + result[at (resultIndex)] +
arg2 * HIGH_U32_FROM_PTR (arg1 + index);
result[at (resultIndex)] = LOW_U32_FROM_VAR (product);
++resultIndex;
}
while (++index < length);
result[at (resultIndex)] += HIGH_U32_FROM_VAR (product);
if (result[at (resultIndex)] < HIGH_U32_FROM_VAR (product))
{
/* must be careful with ++ operator and macro expansion */
++resultIndex;
while (++result[at (resultIndex)] == 0)
++resultIndex;
}
}
#ifndef HY_LITTLE_ENDIAN
void simpleMultiplyAddHighPrecisionBigEndianFix(U_64 *arg1, IDATA length, U_64 arg2, U_32 *result) {
/* Assumes result can hold the product and arg2 only holds 32 bits
of information */
U_64 product;
IDATA index, resultIndex;
index = resultIndex = 0;
product = 0;
do {
product = HIGH_IN_U64(product) + result[halfAt(resultIndex)] + arg2 * LOW_U32_FROM_PTR(arg1 + index);
result[halfAt(resultIndex)] = LOW_U32_FROM_VAR(product);
++resultIndex;
product = HIGH_IN_U64(product) + result[halfAt(resultIndex)] + arg2 * HIGH_U32_FROM_PTR(arg1 + index);
result[halfAt(resultIndex)] = LOW_U32_FROM_VAR(product);
++resultIndex;
} while (++index < length);
result[halfAt(resultIndex)] += HIGH_U32_FROM_VAR(product);
if (result[halfAt(resultIndex)] < HIGH_U32_FROM_VAR(product)) {
/* must be careful with ++ operator and macro expansion */
++resultIndex;
while (++result[halfAt(resultIndex)] == 0) ++resultIndex;
}
}
#endif
void
multiplyHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2,
U_64 * result, IDATA length)
{
/* assumes result is large enough to hold product */
U_64 *temp;
U_32 *resultIn32;
IDATA count, index;
if (length1 < length2)
{
temp = arg1;
arg1 = arg2;
arg2 = temp;
count = length1;
length1 = length2;
length2 = count;
}
memset (result, 0, sizeof (U_64) * length);
/* length1 > length2 */
resultIn32 = (U_32 *) result;
index = -1;
for (count = 0; count < length2; ++count)
{
simpleMultiplyAddHighPrecision (arg1, length1, LOW_IN_U64 (arg2[count]),
resultIn32 + (++index));
#ifdef HY_LITTLE_ENDIAN
simpleMultiplyAddHighPrecision(arg1, length1, HIGH_IN_U64(arg2[count]), resultIn32 + (++index));
#else
simpleMultiplyAddHighPrecisionBigEndianFix(arg1, length1, HIGH_IN_U64(arg2[count]), resultIn32 + (++index));
#endif
}
}
U_32
simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length, U_64 digit)
{
/* assumes digit is less than 32 bits */
U_64 arg;
IDATA index = 0;
digit <<= 32;
do
{
arg = LOW_IN_U64 (arg1[index]);
digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg);
LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit);
arg = HIGH_IN_U64 (arg1[index]);
digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg);
HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit);
}
while (++index < length);
return HIGH_U32_FROM_VAR (digit);
}
void
simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2)
{
/* assumes length > 0 */
IDATA index, offset;
if (arg2 >= 64)
{
offset = arg2 >> 6;
index = length;
while (--index - offset >= 0)
arg1[index] = arg1[index - offset];
do
{
arg1[index] = 0;
}
while (--index >= 0);
arg2 &= 0x3F;
}
if (arg2 == 0)
return;
while (--length > 0)
{
arg1[length] = arg1[length] << arg2 | arg1[length - 1] >> (64 - arg2);
}
*arg1 <<= arg2;
}
IDATA
highestSetBit (U_64 * y)
{
U_32 x;
IDATA result;
if (*y == 0)
return 0;
#if defined(USE_LL)
if (*y & 0xFFFFFFFF00000000LL)
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
else
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
#else
#if defined(USE_L)
if (*y & 0xFFFFFFFF00000000L)
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
else
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
#else
if (*y & 0xFFFFFFFF00000000)
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
else
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
#endif /* USE_L */
#endif /* USE_LL */
if (x & 0xFFFF0000)
{
x = bitSection (x, 0xFFFF0000, 16);
result += 16;
}
if (x & 0xFF00)
{
x = bitSection (x, 0xFF00, 8);
result += 8;
}
if (x & 0xF0)
{
x = bitSection (x, 0xF0, 4);
result += 4;
}
if (x > 0x7)
return result + 4;
else if (x > 0x3)
return result + 3;
else if (x > 0x1)
return result + 2;
else
return result + 1;
}
IDATA
lowestSetBit (U_64 * y)
{
U_32 x;
IDATA result;
if (*y == 0)
return 0;
#if defined(USE_LL)
if (*y & 0x00000000FFFFFFFFLL)
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
else
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
#else
#if defined(USE_L)
if (*y & 0x00000000FFFFFFFFL)
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
else
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
#else
if (*y & 0x00000000FFFFFFFF)
{
x = LOW_U32_FROM_PTR (y);
result = 0;
}
else
{
x = HIGH_U32_FROM_PTR (y);
result = 32;
}
#endif /* USE_L */
#endif /* USE_LL */
if (!(x & 0xFFFF))
{
x = bitSection (x, 0xFFFF0000, 16);
result += 16;
}
if (!(x & 0xFF))
{
x = bitSection (x, 0xFF00, 8);
result += 8;
}
if (!(x & 0xF))
{
x = bitSection (x, 0xF0, 4);
result += 4;
}
if (x & 0x1)
return result + 1;
else if (x & 0x2)
return result + 2;
else if (x & 0x4)
return result + 3;
else
return result + 4;
}
IDATA
highestSetBitHighPrecision (U_64 * arg, IDATA length)
{
IDATA highBit;
while (--length >= 0)
{
highBit = highestSetBit (arg + length);
if (highBit)
return highBit + 64 * length;
}
return 0;
}
IDATA
lowestSetBitHighPrecision (U_64 * arg, IDATA length)
{
IDATA lowBit, index = -1;
while (++index < length)
{
lowBit = lowestSetBit (arg + index);
if (lowBit)
return lowBit + 64 * index;
}
return 0;
}
IDATA
compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2)
{
while (--length1 >= 0 && arg1[length1] == 0);
while (--length2 >= 0 && arg2[length2] == 0);
if (length1 > length2)
return 1;
else if (length1 < length2)
return -1;
else if (length1 > -1)
{
do
{
if (arg1[length1] > arg2[length1])
return 1;
else if (arg1[length1] < arg2[length1])
return -1;
}
while (--length1 >= 0);
}
return 0;
}
KDouble
toDoubleHighPrecision (U_64 * arg, IDATA length)
{
IDATA highBit;
U_64 mantissa, test64;
U_32 test;
KDouble result;
while (length > 0 && arg[length - 1] == 0)
--length;
if (length == 0)
result = 0.0;
else if (length > 16)
{
DOUBLE_TO_LONGBITS (result) = EXPONENT_MASK;
}
else if (length == 1)
{
highBit = highestSetBit (arg);
if (highBit <= 53)
{
highBit = 53 - highBit;
mantissa = *arg << highBit;
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, -highBit);
}
else
{
highBit -= 53;
mantissa = *arg >> highBit;
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, highBit);
/* perform rounding, round to even in case of tie */
test = (LOW_U32_FROM_PTR (arg) << (11 - highBit)) & 0x7FF;
if (test > 0x400 || ((test == 0x400) && (mantissa & 1)))
DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
}
}
else
{
highBit = highestSetBit (arg + (--length));
if (highBit <= 53)
{
highBit = 53 - highBit;
if (highBit > 0)
{
mantissa =
(arg[length] << highBit) | (arg[length - 1] >>
(64 - highBit));
}
else
{
mantissa = arg[length];
}
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, length * 64 - highBit);
/* perform rounding, round to even in case of tie */
test64 = arg[--length] << highBit;
if (test64 > SIGN_MASK || ((test64 == SIGN_MASK) && (mantissa & 1)))
DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
else if (test64 == SIGN_MASK)
{
while (--length >= 0)
{
if (arg[length] != 0)
{
DOUBLE_TO_LONGBITS (result) =
DOUBLE_TO_LONGBITS (result) + 1;
break;
}
}
}
}
else
{
highBit -= 53;
mantissa = arg[length] >> highBit;
DOUBLE_TO_LONGBITS (result) =
CREATE_DOUBLE_BITS (mantissa, length * 64 + highBit);
/* perform rounding, round to even in case of tie */
test = (LOW_U32_FROM_PTR (arg + length) << (11 - highBit)) & 0x7FF;
if (test > 0x400 || ((test == 0x400) && (mantissa & 1)))
DOUBLE_TO_LONGBITS (result) = DOUBLE_TO_LONGBITS (result) + 1;
else if (test == 0x400)
{
do
{
if (arg[--length] != 0)
{
DOUBLE_TO_LONGBITS (result) =
DOUBLE_TO_LONGBITS (result) + 1;
break;
}
}
while (length > 0);
}
}
}
return result;
}
IDATA
tenToTheEHighPrecision (U_64 * result, IDATA length, int e)
{
/* size test */
if (length < ((e / 19) + 1))
return 0;
memset (result, 0, length * sizeof (U_64));
*result = 1;
if (e == 0)
return 1;
length = 1;
length = timesTenToTheEHighPrecision (result, length, e);
/* bad O(n) way of doing it, but simple */
/*
do {
overflow = simpleAppendDecimalDigitHighPrecision(result, length, 0);
if (overflow)
result[length++] = overflow;
} while (--e);
*/
return length;
}
IDATA
timesTenToTheEHighPrecision (U_64 * result, IDATA length, int e)
{
/* assumes result can hold value */
U_64 overflow;
int exp10 = e;
if (e == 0)
return length;
/* bad O(n) way of doing it, but simple */
/*
do {
overflow = simpleAppendDecimalDigitHighPrecision(result, length, 0);
if (overflow)
result[length++] = overflow;
} while (--e);
*/
/* Replace the current implementation which performs a
* "multiplication" by 10 e number of times with an actual
* multiplication. 10e19 is the largest exponent to the power of ten
* that will fit in a 64-bit integer, and 10e9 is the largest exponent to
* the power of ten that will fit in a 64-bit integer. Not sure where the
* break-even point is between an actual multiplication and a
* simpleAappendDecimalDigit() so just pick 10e3 as that point for
* now.
*/
while (exp10 >= 19)
{
overflow = simpleMultiplyHighPrecision64 (result, length, TEN_E19);
if (overflow)
result[length++] = overflow;
exp10 -= 19;
}
while (exp10 >= 9)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E9);
if (overflow)
result[length++] = overflow;
exp10 -= 9;
}
if (exp10 == 0)
return length;
else if (exp10 == 1)
{
overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 2)
{
overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
if (overflow)
result[length++] = overflow;
overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 3)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E3);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 4)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E4);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 5)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E5);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 6)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E6);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 7)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E7);
if (overflow)
result[length++] = overflow;
}
else if (exp10 == 8)
{
overflow = simpleMultiplyHighPrecision (result, length, TEN_E8);
if (overflow)
result[length++] = overflow;
}
return length;
}
U_64
doubleMantissa (KDouble z)
{
U_64 m = DOUBLE_TO_LONGBITS (z);
if ((m & EXPONENT_MASK) != 0)
m = (m & MANTISSA_MASK) | NORMAL_MASK;
else
m = (m & MANTISSA_MASK);
return m;
}
IDATA
doubleExponent (KDouble z)
{
/* assumes positive double */
IDATA k = HIGH_U32_FROM_VAR (z) >> 20;
if (k)
k -= E_OFFSET;
else
k = 1 - E_OFFSET;
return k;
}
UDATA
floatMantissa (KFloat z)
{
UDATA m = (UDATA) FLOAT_TO_INTBITS (z);
if ((m & FLOAT_EXPONENT_MASK) != 0)
m = (m & FLOAT_MANTISSA_MASK) | FLOAT_NORMAL_MASK;
else
m = (m & FLOAT_MANTISSA_MASK);
return m;
}
IDATA
floatExponent (KFloat z)
{
/* assumes positive float */
IDATA k = FLOAT_TO_INTBITS (z) >> 23;
if (k)
k -= FLOAT_E_OFFSET;
else
k = 1 - FLOAT_E_OFFSET;
return k;
}
/* Allow a 64-bit value in arg2 */
U_64
simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2)
{
U_64 intermediate, *pArg1, carry1, carry2, prod1, prod2, sum;
IDATA index;
U_32 buf32;
index = 0;
intermediate = 0;
pArg1 = arg1 + index;
carry1 = carry2 = 0;
do
{
if ((*pArg1 != 0) || (intermediate != 0))
{
prod1 =
(U_64) LOW_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1);
sum = intermediate + prod1;
if ((sum < prod1) || (sum < intermediate))
{
carry1 = 1;
}
else
{
carry1 = 0;
}
prod1 =
(U_64) LOW_U32_FROM_VAR (arg2) * (U_64) HIGH_U32_FROM_PTR (pArg1);
prod2 =
(U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1);
intermediate = carry2 + HIGH_IN_U64 (sum) + prod1 + prod2;
if ((intermediate < prod1) || (intermediate < prod2))
{
carry2 = 1;
}
else
{
carry2 = 0;
}
LOW_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (sum);
buf32 = HIGH_U32_FROM_PTR (pArg1);
HIGH_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (intermediate);
intermediate = carry1 + HIGH_IN_U64 (intermediate)
+ (U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) buf32;
}
pArg1++;
}
while (++index < length);
return intermediate;
}
@@ -0,0 +1,57 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#if !defined(cbigint_h)
#define cbigint_h
#include "fltconst.h"
#include "../Types.h"
//#include "vmi.h"
#define LOW_U32_FROM_VAR(u64) LOW_U32_FROM_LONG64(u64)
#define LOW_U32_FROM_PTR(u64ptr) LOW_U32_FROM_LONG64_PTR(u64ptr)
#define HIGH_U32_FROM_VAR(u64) HIGH_U32_FROM_LONG64(u64)
#define HIGH_U32_FROM_PTR(u64ptr) HIGH_U32_FROM_LONG64_PTR(u64ptr)
#if defined(__cplusplus)
extern "C"
{
#endif
void multiplyHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2,
IDATA length2, U_64 * result, IDATA length);
U_32 simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length, U_64 digit);
KDouble toDoubleHighPrecision (U_64 * arg, IDATA length);
IDATA tenToTheEHighPrecision (U_64 * result, IDATA length, int e);
U_64 doubleMantissa (KDouble z);
IDATA compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2);
IDATA highestSetBitHighPrecision (U_64 * arg, IDATA length);
void subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2);
IDATA doubleExponent (KDouble z);
U_32 simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2);
IDATA addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2);
void simpleMultiplyAddHighPrecisionBigEndianFix (U_64 * arg1, IDATA length, U_64 arg2, U_32 * result);
IDATA lowestSetBit (U_64 * y);
IDATA timesTenToTheEHighPrecision (U_64 * result, IDATA length, int e);
void simpleMultiplyAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2, U_32 * result);
IDATA highestSetBit (U_64 * y);
IDATA lowestSetBitHighPrecision (U_64 * arg, IDATA length);
void simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2);
UDATA floatMantissa (KFloat z);
U_64 simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2);
IDATA simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2);
IDATA floatExponent (KFloat z);
#if defined(__cplusplus)
}
#endif
#endif /* cbigint_h */
@@ -0,0 +1,878 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "cbigint.h"
#include "../Exceptions.h"
#include "../KString.h"
#include "../Natives.h"
#include "../utf8.h"
#if defined(LINUX) || defined(FREEBSD) || defined(ZOS) || defined(MACOSX) || defined(AIX)
#define USE_LL
#endif
#define LOW_I32_FROM_VAR(u64) LOW_I32_FROM_LONG64(u64)
#define LOW_I32_FROM_PTR(u64ptr) LOW_I32_FROM_LONG64_PTR(u64ptr)
#define HIGH_I32_FROM_VAR(u64) HIGH_I32_FROM_LONG64(u64)
#define HIGH_I32_FROM_PTR(u64ptr) HIGH_I32_FROM_LONG64_PTR(u64ptr)
#define MAX_ACCURACY_WIDTH 17
#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
extern "C" {
KDouble Kotlin_native_FloatingPointParser_parseDoubleImpl (KString s, KInt e);
void Kotlin_native_NumberConverter_bigIntDigitGeneratorInstImpl (KRef results,
KRef uArray,
KLong f,
KInt e,
KBoolean isDenormalized,
KBoolean mantissaIsZero,
KInt p);
KDouble Kotlin_native_NumberConverter_ceil(KDouble x) {
return ceil(x);
}
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value);
KDouble Kotlin_native_long_bits_to_double(KLong x);
}
KDouble Kotlin_native_long_bits_to_double(KLong x) {
union {
int64_t x;
double d;
} tmp;
tmp.x = x;
return tmp.d;
}
KDouble createDouble (const char *s, KInt e);
KDouble createDouble1 (U_64 * f, IDATA length, KInt e);
KDouble doubleAlgorithm (U_64 * f, IDATA length, KInt e, KDouble z);
U_64 dblparse_shiftRight64 (U_64 * lp, volatile int mbe);
static const KDouble tens[] = {
1.0,
1.0e1,
1.0e2,
1.0e3,
1.0e4,
1.0e5,
1.0e6,
1.0e7,
1.0e8,
1.0e9,
1.0e10,
1.0e11,
1.0e12,
1.0e13,
1.0e14,
1.0e15,
1.0e16,
1.0e17,
1.0e18,
1.0e19,
1.0e20,
1.0e21,
1.0e22
};
#define tenToTheE(e) (*(tens + (e)))
#define LOG5_OF_TWO_TO_THE_N 23
#define INV_LOG_OF_TEN_BASE_2 (0.30102999566398114)
#define DOUBLE_MIN_VALUE 5.0e-324
#define sizeOfTenToTheE(e) (((e) / 19) + 1)
#if defined(USE_LL)
#define INFINITE_LONGBITS (0x7FF0000000000000LL)
#else
#if defined(USE_L)
#define INFINITE_LONGBITS (0x7FF0000000000000L)
#else
#define INFINITE_LONGBITS (0x7FF0000000000000)
#endif /* USE_L */
#endif /* USE_LL */
#define MINIMUM_LONGBITS (0x1)
#if defined(USE_LL)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFLL)
#define EXPONENT_MASK (0x7FF0000000000000LL)
#define NORMAL_MASK (0x0010000000000000LL)
#else
#if defined(USE_L)
#define MANTISSA_MASK (0x000FFFFFFFFFFFFFL)
#define EXPONENT_MASK (0x7FF0000000000000L)
#define NORMAL_MASK (0x0010000000000000L)
#else
#define MANTISSA_MASK (0x000FFFFFFFFFFFFF)
#define EXPONENT_MASK (0x7FF0000000000000)
#define NORMAL_MASK (0x0010000000000000)
#endif /* USE_L */
#endif /* USE_LL */
#define DOUBLE_TO_LONGBITS(dbl) (*((U_64 *)(&dbl)))
/* Keep a count of the number of times we decrement and increment to
* approximate the double, and attempt to detect the case where we
* could potentially toggle back and forth between decrementing and
* incrementing. It is possible for us to be stuck in the loop when
* incrementing by one or decrementing by one may exceed or stay below
* the value that we are looking for. In this case, just break out of
* the loop if we toggle between incrementing and decrementing for more
* 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; \
} \
}
#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; \
} \
}
#define ERROR_OCCURED(x) (HIGH_I32_FROM_VAR(x) < 0)
#define allocateU64(x, n) if (!((x) = (U_64*) konan::calloc(1, (n) * sizeof(U_64)))) goto OutOfMemory;
#define release(r) if ((r)) konan::free((r));
/*NB the Number converter methods are synchronized so it is possible to
*have global data for use by bigIntDigitGenerator */
#define RM_SIZE 21
#define STemp_SIZE 22
KDouble createDouble (const char *s, KInt e)
{
/* assumes s is a null terminated string with at least one
* character in it */
U_64 def[DEFAULT_WIDTH];
U_64 defBackup[DEFAULT_WIDTH];
U_64 *f, *fNoOverflow, *g, *tempBackup;
U_32 overflow;
KDouble result;
IDATA index = 1;
int unprocessedDigits = 0;
f = def;
fNoOverflow = defBackup;
*f = 0;
tempBackup = g = 0;
do
{
if (*s >= '0' && *s <= '9')
{
/* Make a back up of f before appending, so that we can
* back out of it if there is no more room, i.e. index >
* MAX_ACCURACY_WIDTH.
*/
memcpy (fNoOverflow, f, sizeof (U_64) * index);
overflow =
simpleAppendDecimalDigitHighPrecision (f, index, *s - '0');
if (overflow)
{
f[index++] = overflow;
/* There is an overflow, but there is no more room
* to store the result. We really only need the top 52
* bits anyway, so we must back out of the overflow,
* and ignore the rest of the string.
*/
if (index >= MAX_ACCURACY_WIDTH)
{
index--;
memcpy (f, fNoOverflow, sizeof (U_64) * index);
break;
}
if (tempBackup)
{
fNoOverflow = tempBackup;
}
}
}
else
index = -1;
}
while (index > 0 && *(++s) != '\0');
/* We've broken out of the parse loop either because we've reached
* the end of the string or we've overflowed the maximum accuracy
* limit of a double. If we still have unprocessed digits in the
* given string, then there are three possible results:
* 1. (unprocessed digits + e) == 0, in which case we simply
* convert the existing bits that are already parsed
* 2. (unprocessed digits + e) < 0, in which case we simply
* convert the existing bits that are already parsed along
* with the given e
* 3. (unprocessed digits + e) > 0 indicates that the value is
* simply too big to be stored as a double, so return Infinity
*/
if ((unprocessedDigits = strlen (s)) > 0)
{
e += unprocessedDigits;
if (index > -1)
{
if (e == 0)
result = toDoubleHighPrecision (f, index);
else if (e < 0)
result = createDouble1 (f, index, e);
else
{
DOUBLE_TO_LONGBITS (result) = INFINITE_LONGBITS;
}
}
else
{
LOW_I32_FROM_VAR (result) = -1;
HIGH_I32_FROM_VAR (result) = -1;
}
}
else
{
if (index > -1)
{
if (e == 0)
result = toDoubleHighPrecision (f, index);
else
result = createDouble1 (f, index, e);
}
else
{
LOW_I32_FROM_VAR (result) = -1;
HIGH_I32_FROM_VAR (result) = -1;
}
}
return result;
}
KDouble
createDouble1 (U_64 * f, IDATA length, KInt e)
{
IDATA numBits;
KDouble result;
#define APPROX_MIN_MAGNITUDE -309
#define APPROX_MAX_MAGNITUDE 309
numBits = highestSetBitHighPrecision (f, length) + 1;
numBits -= lowestSetBitHighPrecision (f, length);
if (numBits < 54 && e >= 0 && e < LOG5_OF_TWO_TO_THE_N)
{
return toDoubleHighPrecision (f, length) * tenToTheE (e);
}
else if (numBits < 54 && e < 0 && (-e) < LOG5_OF_TWO_TO_THE_N)
{
return toDoubleHighPrecision (f, length) / tenToTheE (-e);
}
else if (e >= 0 && e < APPROX_MAX_MAGNITUDE)
{
result = toDoubleHighPrecision (f, length) * pow (10.0, (double) e);
}
else if (e >= APPROX_MAX_MAGNITUDE)
{
/* Convert the partial result to make sure that the
* non-exponential part is not zero. This check fixes the case
* where the user enters 0.0e309! */
result = toDoubleHighPrecision (f, length);
/* Don't go straight to zero as the fact that x*0 = 0 independent of x might
cause the algorithm to produce an incorrect result. Instead try the min value
first and let it fall to zero if need be. */
if (result == 0.0)
DOUBLE_TO_LONGBITS (result) = MINIMUM_LONGBITS;
else
DOUBLE_TO_LONGBITS (result) = INFINITE_LONGBITS;
}
else if (e > APPROX_MIN_MAGNITUDE)
{
result = toDoubleHighPrecision (f, length) / pow (10.0, (double) -e);
}
if (e <= APPROX_MIN_MAGNITUDE)
{
result = toDoubleHighPrecision (f, length) * pow (10.0, (double) (e + 52));
result = result * pow (10.0, (double) -52);
}
/* Don't go straight to zero as the fact that x*0 = 0 independent of x might
cause the algorithm to produce an incorrect result. Instead try the min value
first and let it fall to zero if need be. */
if (result == 0.0)
DOUBLE_TO_LONGBITS (result) = MINIMUM_LONGBITS;
return doubleAlgorithm (f, length, e, result);
}
U_64
dblparse_shiftRight64 (U_64 * lp, volatile int mbe)
{
U_64 b1Value = 0;
U_32 hi = HIGH_U32_FROM_LONG64_PTR (lp);
U_32 lo = LOW_U32_FROM_LONG64_PTR (lp);
int srAmt;
if (mbe == 0)
return 0;
if (mbe >= 128)
{
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
return 0;
}
/* Certain platforms do not handle de-referencing a 64-bit value
* from a pointer on the stack correctly (e.g. MVL-hh/XScale)
* because the pointer may not be properly aligned, so we'll have
* to handle two 32-bit chunks. */
if (mbe < 32)
{
LOW_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64 (b1Value) = lo << (32 - mbe);
LOW_U32_FROM_LONG64_PTR (lp) = (hi << (32 - mbe)) | (lo >> mbe);
HIGH_U32_FROM_LONG64_PTR (lp) = hi >> mbe;
}
else if (mbe == 32)
{
LOW_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64 (b1Value) = lo;
LOW_U32_FROM_LONG64_PTR (lp) = hi;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
}
else if (mbe < 64)
{
srAmt = mbe - 32;
LOW_U32_FROM_LONG64 (b1Value) = lo << (32 - srAmt);
HIGH_U32_FROM_LONG64 (b1Value) = (hi << (32 - srAmt)) | (lo >> srAmt);
LOW_U32_FROM_LONG64_PTR (lp) = hi >> srAmt;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
}
else if (mbe == 64)
{
LOW_U32_FROM_LONG64 (b1Value) = lo;
HIGH_U32_FROM_LONG64 (b1Value) = hi;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
}
else if (mbe < 96)
{
srAmt = mbe - 64;
b1Value = *lp;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64 (b1Value) >>= srAmt;
LOW_U32_FROM_LONG64 (b1Value) |= (hi << (32 - srAmt));
HIGH_U32_FROM_LONG64 (b1Value) >>= srAmt;
}
else if (mbe == 96)
{
LOW_U32_FROM_LONG64 (b1Value) = hi;
HIGH_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
}
else
{
LOW_U32_FROM_LONG64 (b1Value) = hi >> (mbe - 96);
HIGH_U32_FROM_LONG64 (b1Value) = 0;
HIGH_U32_FROM_LONG64_PTR (lp) = 0;
LOW_U32_FROM_LONG64_PTR (lp) = 0;
}
return b1Value;
}
#if defined(WIN32)
/* disable global optimizations on the microsoft compiler for the
* doubleAlgorithm function otherwise it won't compile */
#pragma optimize("g",off)
#endif
/* The algorithm for the function doubleAlgorithm() below can be found
* in:
*
* "How to Read Floating-Point Numbers Accurately", William D.
* Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
* Programming Language Design and Implementation, June 20-22,
* 1990, pp. 92-101.
*
* There is a possibility that the function will end up in an endless
* loop if the given approximating floating-point number (a very small
* floating-point whose value is very close to zero) straddles between
* two approximating integer values. We modified the algorithm slightly
* to detect the case where it oscillates back and forth between
* incrementing and decrementing the floating-point approximation. It
* is currently set such that if the oscillation occurs more than twice
* then return the original approximation.
*/
KDouble doubleAlgorithm (U_64 * f, IDATA length, KInt e, KDouble z)
{
U_64 m;
IDATA k, comparison, comparison2;
U_64 *x, *y, *D, *D2;
IDATA xLength, yLength, DLength, D2Length, decApproxCount, incApproxCount;
//PORT_ACCESS_FROM_ENV (env);
x = y = D = D2 = 0;
xLength = yLength = DLength = D2Length = 0;
decApproxCount = incApproxCount = 0;
do
{
m = doubleMantissa (z);
k = doubleExponent (z);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
if (e >= 0 && k >= 0)
{
xLength = sizeOfTenToTheE (e) + length;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
yLength = (k >> 6) + 2;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
simpleShiftLeftHighPrecision (y, yLength, k);
}
else if (e >= 0)
{
xLength = sizeOfTenToTheE (e) + length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = 1;
allocateU64 (y, 1);
*y = m;
}
else if (k >= 0)
{
xLength = length;
x = f;
yLength = sizeOfTenToTheE (-e) + 2 + (k >> 6);
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
simpleShiftLeftHighPrecision (y, yLength, k);
}
else
{
xLength = length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = sizeOfTenToTheE (-e) + 1;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
}
comparison = compareHighPrecision (x, xLength, y, yLength);
if (comparison > 0)
{ /* x > y */
DLength = xLength;
allocateU64 (D, DLength);
memcpy (D, x, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, y, yLength);
}
else if (comparison)
{ /* y > x */
DLength = yLength;
allocateU64 (D, DLength);
memcpy (D, y, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, x, xLength);
}
else
{ /* y == x */
DLength = 1;
allocateU64 (D, 1);
*D = 0;
}
D2Length = DLength + 1;
allocateU64 (D2, D2Length);
m <<= 1;
multiplyHighPrecision (D, DLength, &m, 1, D2, D2Length);
m >>= 1;
comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
if (comparison2 < 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
simpleShiftLeftHighPrecision (D2, D2Length, 1);
if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else
{
break;
}
}
else if (comparison2 == 0)
{
if ((LOW_U32_FROM_VAR (m) & 1) == 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else if (comparison < 0)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
break;
}
else
{
INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
break;
}
}
else if (comparison < 0)
{
DECREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
else
{
if (DOUBLE_TO_LONGBITS (z) == INFINITE_LONGBITS)
break;
INCREMENT_DOUBLE (z, decApproxCount, incApproxCount);
}
}
while (1);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
return z;
OutOfMemory:
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
DOUBLE_TO_LONGBITS (z) = -2;
return z;
}
#if defined(WIN32)
#pragma optimize("",on) /*restore optimizations */
#endif
KDouble Kotlin_native_FloatingPointParser_parseDoubleImpl (KString s, KInt e)
{
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
KStdString utf8;
utf8.reserve(s->count_);
TRY_CATCH(utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)),
utf8::unchecked::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)),
/* Illegal UTF-16 string. */ ThrowNumberFormatException());
const char *str = utf8.c_str();
auto dbl = createDouble (str, e);
if (!ERROR_OCCURED (dbl))
{
return dbl;
}
else if (LOW_I32_FROM_VAR (dbl) == (I_32) - 1)
{ /* NumberFormatException */
ThrowNumberFormatException();
}
else
{ /* OutOfMemoryError */
ThrowOutOfMemoryError();
}
return 0.0;
}
/* The algorithm for this particular function can be found in:
*
* Printing Floating-Point Numbers Quickly and Accurately, Robert
* G. Burger, and R. Kent Dybvig, Programming Language Design and
* Implementation (PLDI) 1996, pp.108-116.
*
* The previous implementation of this function combined m+ and m- into
* one single M which caused some inaccuracy of the last digit. The
* particular case below shows this inaccuracy:
*
* System.out.println(new Double((1.234123412431233E107)).toString());
* System.out.println(new Double((1.2341234124312331E107)).toString());
* System.out.println(new Double((1.2341234124312332E107)).toString());
*
* outputs the following:
*
* 1.234123412431233E107
* 1.234123412431233E107
* 1.234123412431233E107
*
* instead of:
*
* 1.234123412431233E107
* 1.2341234124312331E107
* 1.2341234124312331E107
*
*/
void Kotlin_native_NumberConverter_bigIntDigitGeneratorInstImpl (KRef results,
KRef uArray,
KLong f,
KInt e,
KBoolean isDenormalized,
KBoolean mantissaIsZero,
KInt p)
{
int RLength, SLength, TempLength, mplus_Length, mminus_Length;
int high, low, i;
int k, firstK, U;
int getCount, setCount;
U_64 R[RM_SIZE], S[STemp_SIZE], mplus[RM_SIZE], mminus[RM_SIZE], Temp[STemp_SIZE];
memset (R, 0, RM_SIZE * sizeof (U_64));
memset (S, 0, STemp_SIZE * sizeof (U_64));
memset (mplus, 0, RM_SIZE * sizeof (U_64));
memset (mminus, 0, RM_SIZE * sizeof (U_64));
memset (Temp, 0, STemp_SIZE * sizeof (U_64));
if (e >= 0)
{
*R = f;
*mplus = *mminus = 1;
simpleShiftLeftHighPrecision (mminus, RM_SIZE, e);
if (f != (2 << (p - 1)))
{
simpleShiftLeftHighPrecision (R, RM_SIZE, e + 1);
*S = 2;
/*
* m+ = m+ << e results in 1.0e23 to be printed as
* 0.9999999999999999E23
* m+ = m+ << e+1 results in 1.0e23 to be printed as
* 1.0e23 (caused too much rounding)
* 470fffffffffffff = 2.0769187434139308E34
* 4710000000000000 = 2.076918743413931E34
*/
simpleShiftLeftHighPrecision (mplus, RM_SIZE, e);
}
else
{
simpleShiftLeftHighPrecision (R, RM_SIZE, e + 2);
*S = 4;
simpleShiftLeftHighPrecision (mplus, RM_SIZE, e + 1);
}
}
else
{
if (isDenormalized || (f != (2 << (p - 1))))
{
*R = f << 1;
*S = 1;
simpleShiftLeftHighPrecision (S, STemp_SIZE, 1 - e);
*mplus = *mminus = 1;
}
else
{
*R = f << 2;
*S = 1;
simpleShiftLeftHighPrecision (S, STemp_SIZE, 2 - e);
*mplus = 2;
*mminus = 1;
}
}
k = (int) ceil ((e + p - 1) * INV_LOG_OF_TEN_BASE_2 - 1e-10);
if (k > 0)
{
timesTenToTheEHighPrecision (S, STemp_SIZE, k);
}
else
{
timesTenToTheEHighPrecision (R, RM_SIZE, -k);
timesTenToTheEHighPrecision (mplus, RM_SIZE, -k);
timesTenToTheEHighPrecision (mminus, RM_SIZE, -k);
}
RLength = mplus_Length = mminus_Length = RM_SIZE;
SLength = TempLength = STemp_SIZE;
memset (Temp + RM_SIZE, 0, (STemp_SIZE - RM_SIZE) * sizeof (U_64));
memcpy (Temp, R, RM_SIZE * sizeof (U_64));
while (RLength > 1 && R[RLength - 1] == 0)
--RLength;
while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
--mplus_Length;
while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
--mminus_Length;
while (SLength > 1 && S[SLength - 1] == 0)
--SLength;
TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1;
addHighPrecision (Temp, TempLength, mplus, mplus_Length);
if (compareHighPrecision (Temp, TempLength, S, SLength) >= 0)
{
firstK = k;
}
else
{
firstK = k - 1;
simpleAppendDecimalDigitHighPrecision (R, ++RLength, 0);
simpleAppendDecimalDigitHighPrecision (mplus, ++mplus_Length, 0);
simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0);
while (RLength > 1 && R[RLength - 1] == 0)
--RLength;
while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
--mplus_Length;
while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
--mminus_Length;
}
getCount = setCount = 0;
do
{
U = 0;
for (i = 3; i >= 0; --i)
{
TempLength = SLength + 1;
Temp[SLength] = 0;
memcpy (Temp, S, SLength * sizeof (U_64));
simpleShiftLeftHighPrecision (Temp, TempLength, i);
if (compareHighPrecision (R, RLength, Temp, TempLength) >= 0)
{
subtractHighPrecision (R, RLength, Temp, TempLength);
U += 1 << i;
}
}
low = compareHighPrecision (R, RLength, mminus, mminus_Length) <= 0;
memset (Temp + RLength, 0, (STemp_SIZE - RLength) * sizeof (U_64));
memcpy (Temp, R, RLength * sizeof (U_64));
TempLength = (RLength > mplus_Length ? RLength : mplus_Length) + 1;
addHighPrecision (Temp, TempLength, mplus, mplus_Length);
high = compareHighPrecision (Temp, TempLength, S, SLength) >= 0;
if (low || high)
break;
simpleAppendDecimalDigitHighPrecision (R, ++RLength, 0);
simpleAppendDecimalDigitHighPrecision (mplus, ++mplus_Length, 0);
simpleAppendDecimalDigitHighPrecision (mminus, ++mminus_Length, 0);
while (RLength > 1 && R[RLength - 1] == 0)
--RLength;
while (mplus_Length > 1 && mplus[mplus_Length - 1] == 0)
--mplus_Length;
while (mminus_Length > 1 && mminus[mminus_Length - 1] == 0)
--mminus_Length;
Kotlin_IntArray_set(uArray, setCount++, U);
//uArray[setCount++] = U;
}
while (1);
simpleShiftLeftHighPrecision (R, ++RLength, 1);
if (low && !high)
Kotlin_IntArray_set(uArray, setCount++, U);
//uArray[setCount++] = U;
else if (high && !low)
Kotlin_IntArray_set(uArray, setCount++, U + 1);
//uArray[setCount++] = U + 1;
else if (compareHighPrecision (R, RLength, S, SLength) < 0)
Kotlin_IntArray_set(uArray, setCount++, U);
//uArray[setCount++] = U;
else
Kotlin_IntArray_set(uArray, setCount++, U + 1);
//uArray[setCount++] = U + 1;
Kotlin_IntArray_set(results, 0, setCount);
// fid = (*env)->GetFieldID (env, clazz, "setCount", "I");
// (*env)->SetIntField (env, inst, fid, setCount);
Kotlin_IntArray_set(results, 1, getCount);
// fid = (*env)->GetFieldID (env, clazz, "getCount", "I");
// (*env)->SetIntField (env, inst, fid, getCount);
Kotlin_IntArray_set(results, 2, firstK);
// fid = (*env)->GetFieldID (env, clazz, "firstK", "I");
// (*env)->SetIntField (env, inst, fid, firstK);
}
@@ -0,0 +1,160 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#if !defined(fltconst_h)
#define fltconst_h
#include "hycomp.h"
/* IEEE floats consist of: sign bit, exponent field, significand field
single: 31 = sign bit, 30..23 = exponent (8 bits), 22..0 = significand (23 bits)
double: 63 = sign bit, 62..52 = exponent (11 bits), 51..0 = significand (52 bits)
inf == (all exponent bits set) and (all mantissa bits clear)
nan == (all exponent bits set) and (at least one mantissa bit set)
finite == (at least one exponent bit clear)
zero == (all exponent bits clear) and (all mantissa bits clear)
denormal == (all exponent bits clear) and (at least one mantissa bit set)
positive == sign bit clear
negative == sign bit set
*/
#define MAX_U32_DOUBLE (ESDOUBLE) (4294967296.0) /* 2^32 */
#define MAX_U32_SINGLE (ESSINGLE) (4294967296.0) /* 2^32 */
#define HY_POS_PI (ESDOUBLE)(3.141592653589793)
#ifdef HY_LITTLE_ENDIAN
#ifdef HY_PLATFORM_DOUBLE_ORDER
#define DOUBLE_LO_OFFSET 0
#define DOUBLE_HI_OFFSET 1
#else
#define DOUBLE_LO_OFFSET 1
#define DOUBLE_HI_OFFSET 0
#endif
#define LONG_LO_OFFSET 0
#define LONG_HI_OFFSET 1
#else
#ifdef HY_PLATFORM_DOUBLE_ORDER
#define DOUBLE_LO_OFFSET 1
#define DOUBLE_HI_OFFSET 0
#else
#define DOUBLE_LO_OFFSET 0
#define DOUBLE_HI_OFFSET 1
#endif
#define LONG_LO_OFFSET 1
#define LONG_HI_OFFSET 0
#endif
#define RETURN_FINITE 0
#define RETURN_NAN 1
#define RETURN_POS_INF 2
#define RETURN_NEG_INF 3
#define DOUBLE_SIGN_MASK_HI 0x80000000
#define DOUBLE_EXPONENT_MASK_HI 0x7FF00000
#define DOUBLE_MANTISSA_MASK_LO 0xFFFFFFFF
#define DOUBLE_MANTISSA_MASK_HI 0x000FFFFF
#define SINGLE_SIGN_MASK 0x80000000
#define SINGLE_EXPONENT_MASK 0x7F800000
#define SINGLE_MANTISSA_MASK 0x007FFFFF
#define SINGLE_NAN_BITS (SINGLE_EXPONENT_MASK | 0x00400000)
typedef union u64u32dbl_tag {
U_64 u64val;
U_32 u32val[2];
I_32 i32val[2];
double dval;
} U64U32DBL;
/* Replace P_FLOAT_HI and P_FLOAT_LOW */
/* These macros are used to access the high and low 32-bit parts of a double (64-bit) value. */
#define LOW_U32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->u32val[DOUBLE_LO_OFFSET])
#define HIGH_U32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->u32val[DOUBLE_HI_OFFSET])
#define LOW_I32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->i32val[DOUBLE_LO_OFFSET])
#define HIGH_I32_FROM_DBL_PTR(dblptr) (((U64U32DBL *)(dblptr))->i32val[DOUBLE_HI_OFFSET])
#define LOW_U32_FROM_DBL(dbl) LOW_U32_FROM_DBL_PTR(&(dbl))
#define HIGH_U32_FROM_DBL(dbl) HIGH_U32_FROM_DBL_PTR(&(dbl))
#define LOW_I32_FROM_DBL(dbl) LOW_I32_FROM_DBL_PTR(&(dbl))
#define HIGH_I32_FROM_DBL(dbl) HIGH_I32_FROM_DBL_PTR(&(dbl))
#define LOW_U32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->u32val[LONG_LO_OFFSET])
#define HIGH_U32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->u32val[LONG_HI_OFFSET])
#define LOW_I32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->i32val[LONG_LO_OFFSET])
#define HIGH_I32_FROM_LONG64_PTR(long64ptr) (((U64U32DBL *)(long64ptr))->i32val[LONG_HI_OFFSET])
#define LOW_U32_FROM_LONG64(long64) LOW_U32_FROM_LONG64_PTR(&(long64))
#define HIGH_U32_FROM_LONG64(long64) HIGH_U32_FROM_LONG64_PTR(&(long64))
#define LOW_I32_FROM_LONG64(long64) LOW_I32_FROM_LONG64_PTR(&(long64))
#define HIGH_I32_FROM_LONG64(long64) HIGH_I32_FROM_LONG64_PTR(&(long64))
#define IS_ZERO_DBL_PTR(dblptr) ((LOW_U32_FROM_DBL_PTR(dblptr) == 0) && ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0) || (HIGH_U32_FROM_DBL_PTR(dblptr) == DOUBLE_SIGN_MASK_HI)))
#define IS_ONE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0x3ff00000 || HIGH_U32_FROM_DBL_PTR(dblptr) == 0xbff00000) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0))
#define IS_NAN_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) == DOUBLE_EXPONENT_MASK_HI) && (LOW_U32_FROM_DBL_PTR(dblptr) | (HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_MANTISSA_MASK_HI)))
#define IS_INF_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & (DOUBLE_EXPONENT_MASK_HI|DOUBLE_MANTISSA_MASK_HI)) == DOUBLE_EXPONENT_MASK_HI) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0))
#define IS_DENORMAL_DBL_PTR(dblptr) (((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) == 0) && ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_MANTISSA_MASK_HI) != 0 || (LOW_U32_FROM_DBL_PTR(dblptr) != 0)))
#define IS_FINITE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_EXPONENT_MASK_HI) < DOUBLE_EXPONENT_MASK_HI)
#define IS_POSITIVE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_SIGN_MASK_HI) == 0)
#define IS_NEGATIVE_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) & DOUBLE_SIGN_MASK_HI) != 0)
#define IS_NEGATIVE_MAX_DBL_PTR(dblptr) ((HIGH_U32_FROM_DBL_PTR(dblptr) == 0xFFEFFFFF) && (LOW_U32_FROM_DBL_PTR(dblptr) == 0xFFFFFFFF))
#define IS_ZERO_DBL(dbl) IS_ZERO_DBL_PTR(&(dbl))
#define IS_ONE_DBL(dbl) IS_ONE_DBL_PTR(&(dbl))
#define IS_NAN_DBL(dbl) IS_NAN_DBL_PTR(&(dbl))
#define IS_INF_DBL(dbl) IS_INF_DBL_PTR(&(dbl))
#define IS_DENORMAL_DBL(dbl) IS_DENORMAL_DBL_PTR(&(dbl))
#define IS_FINITE_DBL(dbl) IS_FINITE_DBL_PTR(&(dbl))
#define IS_POSITIVE_DBL(dbl) IS_POSITIVE_DBL_PTR(&(dbl))
#define IS_NEGATIVE_DBL(dbl) IS_NEGATIVE_DBL_PTR(&(dbl))
#define IS_NEGATIVE_MAX_DBL(dbl) IS_NEGATIVE_MAX_DBL_PTR(&(dbl))
#define IS_ZERO_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) == (U_32)0)
#define IS_ONE_SNGL_PTR(fltptr) ((*U32P((fltptr)) == 0x3f800000) || (*U32P((fltptr)) == 0xbf800000))
#define IS_NAN_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) > (U_32)SINGLE_EXPONENT_MASK)
#define IS_INF_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) == (U_32)SINGLE_EXPONENT_MASK)
#define IS_DENORMAL_SNGL_PTR(fltptr) (((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK)-(U_32)1) < (U_32)SINGLE_MANTISSA_MASK)
#define IS_FINITE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)~SINGLE_SIGN_MASK) < (U_32)SINGLE_EXPONENT_MASK)
#define IS_POSITIVE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)SINGLE_SIGN_MASK) == (U_32)0)
#define IS_NEGATIVE_SNGL_PTR(fltptr) ((*U32P((fltptr)) & (U_32)SINGLE_SIGN_MASK) != (U_32)0)
#define IS_ZERO_SNGL(flt) IS_ZERO_SNGL_PTR(&(flt))
#define IS_ONE_SNGL(flt) IS_ONE_SNGL_PTR(&(flt))
#define IS_NAN_SNGL(flt) IS_NAN_SNGL_PTR(&(flt))
#define IS_INF_SNGL(flt) IS_INF_SNGL_PTR(&(flt))
#define IS_DENORMAL_SNGL(flt) IS_DENORMAL_SNGL_PTR(&(flt))
#define IS_FINITE_SNGL(flt) IS_FINITE_SNGL_PTR(&(flt))
#define IS_POSITIVE_SNGL(flt) IS_POSITIVE_SNGL_PTR(&(flt))
#define IS_NEGATIVE_SNGL(flt) IS_NEGATIVE_SNGL_PTR(&(flt))
#define SET_NAN_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = (DOUBLE_EXPONENT_MASK_HI | 0x00080000); LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_PZERO_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = 0; LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_NZERO_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = DOUBLE_SIGN_MASK_HI; LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_PINF_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = DOUBLE_EXPONENT_MASK_HI; LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_NINF_DBL_PTR(dblptr) HIGH_U32_FROM_DBL_PTR(dblptr) = (DOUBLE_EXPONENT_MASK_HI | DOUBLE_SIGN_MASK_HI); LOW_U32_FROM_DBL_PTR(dblptr) = 0
#define SET_NAN_SNGL_PTR(fltptr) *U32P((fltptr)) = ((U_32)SINGLE_NAN_BITS)
#define SET_PZERO_SNGL_PTR(fltptr) *U32P((fltptr)) = 0
#define SET_NZERO_SNGL_PTR(fltptr) *U32P((fltptr)) = SINGLE_SIGN_MASK
#define SET_PINF_SNGL_PTR(fltptr) *U32P((fltptr)) = SINGLE_EXPONENT_MASK
#define SET_NINF_SNGL_PTR(fltptr) *U32P((fltptr)) = (SINGLE_EXPONENT_MASK | SINGLE_SIGN_MASK)
#if defined(HY_WORD64)
#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) ((U64U32DBL *)(aDoublePtr))->u64val = ((U64U32DBL *)(dstPtr))->u64val
#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) ((U64U32DBL *)(dstPtr))->u64val = ((U64U32DBL *)(aDoublePtr))->u64val
#define STORE_LONG(dstPtr, hi, lo) ((U64U32DBL *)(dstPtr))->u64val = (((U_64)(hi)) << 32) | (lo)
#else
/* on some platforms (HP720) we cannot reference an unaligned float. Build them by hand, one U_32 at a time. */
#if defined(ATOMIC_FLOAT_ACCESS)
#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) HIGH_U32_FROM_DBL_PTR(dstPtr) = HIGH_U32_FROM_DBL_PTR(aDoublePtr); LOW_U32_FROM_DBL_PTR(dstPtr) = LOW_U32_FROM_DBL_PTR(aDoublePtr)
#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) HIGH_U32_FROM_DBL_PTR(aDoublePtr) = HIGH_U32_FROM_DBL_PTR(dstPtr); LOW_U32_FROM_DBL_PTR(aDoublePtr) = LOW_U32_FROM_DBL_PTR(dstPtr)
#else
#define PTR_DOUBLE_STORE(dstPtr, aDoublePtr) (*(dstPtr) = *(aDoublePtr))
#define PTR_DOUBLE_VALUE(dstPtr, aDoublePtr) (*(aDoublePtr) = *(dstPtr))
#endif
#define STORE_LONG(dstPtr, hi, lo) HIGH_U32_FROM_LONG64_PTR(dstPtr) = (hi); LOW_U32_FROM_LONG64_PTR(dstPtr) = (lo)
#endif /* HY_WORD64 */
#define PTR_SINGLE_VALUE(dstPtr, aSinglePtr) (*U32P(aSinglePtr) = *U32P(dstPtr))
#define PTR_SINGLE_STORE(dstPtr, aSinglePtr) *((U_32 *)(dstPtr)) = (*U32P(aSinglePtr))
#endif /* fltconst_h */
@@ -0,0 +1,563 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "cbigint.h"
#include "../Exceptions.h"
#include "../KString.h"
#include "../Natives.h"
#include "../utf8.h"
#if defined(LINUX) || defined(FREEBSD) || defined(MACOSX) || defined(ZOS) || defined(AIX)
#define USE_LL
#endif
#ifdef HY_LITTLE_ENDIAN
#define LOW_I32_FROM_PTR(ptr64) (*(I_32 *) (ptr64))
#else
#define LOW_I32_FROM_PTR(ptr64) (*(((I_32 *) (ptr64)) + 1))
#endif
#define MAX_ACCURACY_WIDTH 8
#define DEFAULT_WIDTH MAX_ACCURACY_WIDTH
extern "C" KFloat Kotlin_native_int_bits_to_float(KInt x) {
union {
int32_t x;
float f;
} tmp;
tmp.x = x;
return tmp.f;
}
KFloat createFloat1 (U_64 * f, IDATA length, KInt e);
KFloat floatAlgorithm (U_64 * f, IDATA length, KInt e, KFloat z);
KFloat createFloat (const char *s, KInt e);
static const U_32 tens[] = {
0x3f800000,
0x41200000,
0x42c80000,
0x447a0000,
0x461c4000,
0x47c35000,
0x49742400,
0x4b189680,
0x4cbebc20,
0x4e6e6b28,
0x501502f9 /* 10 ^ 10 in float */
};
#define tenToTheE(e) (*((KFloat *) (tens + (e))))
#define LOG5_OF_TWO_TO_THE_N 11
#define sizeOfTenToTheE(e) (((e) / 19) + 1)
#define INFINITE_INTBITS (0x7F800000)
#define MINIMUM_INTBITS (1)
#define MANTISSA_MASK (0x007FFFFF)
#define EXPONENT_MASK (0x7F800000)
#define NORMAL_MASK (0x00800000)
#define FLOAT_TO_INTBITS(flt) (*((U_32 *)(&flt)))
/* Keep a count of the number of times we decrement and increment to
* approximate the double, and attempt to detect the case where we
* could potentially toggle back and forth between decrementing and
* incrementing. It is possible for us to be stuck in the loop when
* incrementing by one or decrementing by one may exceed or stay below
* the value that we are looking for. In this case, just break out of
* the loop if we toggle between incrementing and decrementing for more
* than twice.
*/
#define INCREMENT_FLOAT(_x, _decCount, _incCount) \
{ \
++FLOAT_TO_INTBITS(_x); \
_incCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \
FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \
FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
} \
break; \
} \
}
#define DECREMENT_FLOAT(_x, _decCount, _incCount) \
{ \
--FLOAT_TO_INTBITS(_x); \
_decCount++; \
if( (_incCount > 2) && (_decCount > 2) ) { \
if( _decCount > _incCount ) { \
FLOAT_TO_INTBITS(_x) += _decCount - _incCount; \
} else if( _incCount > _decCount ) { \
FLOAT_TO_INTBITS(_x) -= _incCount - _decCount; \
} \
break; \
} \
}
#define allocateU64(x, n) if (!((x) = (U_64*) konan::calloc(1, (n) * sizeof(U_64)))) goto OutOfMemory;
#define release(r) if ((r)) konan::free((r));
KFloat createFloat(const char *s, KInt e) {
/* assumes s is a null terminated string with at least one
* character in it */
U_64 def[DEFAULT_WIDTH];
U_64 defBackup[DEFAULT_WIDTH];
U_64 *f, *fNoOverflow, *g, *tempBackup;
U_32 overflow;
KFloat result;
IDATA index = 1;
int unprocessedDigits = 0;
f = def;
fNoOverflow = defBackup;
*f = 0;
tempBackup = g = 0;
do
{
if (*s >= '0' && *s <= '9')
{
/* Make a back up of f before appending, so that we can
* back out of it if there is no more room, i.e. index >
* MAX_ACCURACY_WIDTH.
*/
memcpy (fNoOverflow, f, sizeof (U_64) * index);
overflow =
simpleAppendDecimalDigitHighPrecision (f, index, *s - '0');
if (overflow)
{
f[index++] = overflow;
/* There is an overflow, but there is no more room
* to store the result. We really only need the top 52
* bits anyway, so we must back out of the overflow,
* and ignore the rest of the string.
*/
if (index >= MAX_ACCURACY_WIDTH)
{
index--;
memcpy (f, fNoOverflow, sizeof (U_64) * index);
break;
}
if (tempBackup)
{
fNoOverflow = tempBackup;
}
}
}
else
index = -1;
}
while (index > 0 && *(++s) != '\0');
/* We've broken out of the parse loop either because we've reached
* the end of the string or we've overflowed the maximum accuracy
* limit of a double. If we still have unprocessed digits in the
* given string, then there are three possible results:
* 1. (unprocessed digits + e) == 0, in which case we simply
* convert the existing bits that are already parsed
* 2. (unprocessed digits + e) < 0, in which case we simply
* convert the existing bits that are already parsed along
* with the given e
* 3. (unprocessed digits + e) > 0 indicates that the value is
* simply too big to be stored as a double, so return Infinity
*/
if ((unprocessedDigits = strlen (s)) > 0)
{
e += unprocessedDigits;
if (index > -1)
{
if (e <= 0)
{
result = createFloat1 (f, index, e);
}
else
{
FLOAT_TO_INTBITS (result) = INFINITE_INTBITS;
}
}
else
{
result = *(KFloat *) & index;
}
}
else
{
if (index > -1)
{
result = createFloat1 (f, index, e);
}
else
{
result = *(KFloat *) & index;
}
}
return result;
}
KFloat
createFloat1 (U_64 * f, IDATA length, KInt e)
{
IDATA numBits;
KDouble dresult;
KFloat result;
numBits = highestSetBitHighPrecision (f, length) + 1;
if (numBits < 25 && e >= 0 && e < LOG5_OF_TWO_TO_THE_N)
{
return ((KFloat) LOW_I32_FROM_PTR (f)) * tenToTheE (e);
}
else if (numBits < 25 && e < 0 && (-e) < LOG5_OF_TWO_TO_THE_N)
{
return ((KFloat) LOW_I32_FROM_PTR (f)) / tenToTheE (-e);
}
else if (e >= 0 && e < 39)
{
result = (KFloat) (toDoubleHighPrecision (f, length) * pow (10.0, (double) e));
}
else if (e >= 39)
{
/* Convert the partial result to make sure that the
* non-exponential part is not zero. This check fixes the case
* where the user enters 0.0e309! */
result = (KFloat) toDoubleHighPrecision (f, length);
if (result == 0.0)
FLOAT_TO_INTBITS (result) = MINIMUM_INTBITS;
else
FLOAT_TO_INTBITS (result) = INFINITE_INTBITS;
}
else if (e > -309)
{
int dexp;
U_32 fmant, fovfl;
U_64 dmant;
dresult = toDoubleHighPrecision (f, length) / pow (10.0, (double) -e);
if (IS_DENORMAL_DBL (dresult))
{
FLOAT_TO_INTBITS (result) = 0;
return result;
}
dexp = doubleExponent (dresult) + 51;
dmant = doubleMantissa (dresult);
/* Is it too small to be represented by a single-precision
* float? */
if (dexp <= -155)
{
FLOAT_TO_INTBITS (result) = 0;
return result;
}
/* Is it a denormalized single-precision float? */
if ((dexp <= -127) && (dexp > -155))
{
/* Only interested in 24 msb bits of the 53-bit double mantissa */
fmant = (U_32) (dmant >> 29);
fovfl = ((U_32) (dmant & 0x1FFFFFFF)) << 3;
while ((dexp < -127) && ((fmant | fovfl) != 0))
{
if ((fmant & 1) != 0)
{
fovfl |= 0x80000000;
}
fovfl >>= 1;
fmant >>= 1;
dexp++;
}
if ((fovfl & 0x80000000) != 0)
{
if ((fovfl & 0x7FFFFFFC) != 0)
{
fmant++;
}
else if ((fmant & 1) != 0)
{
fmant++;
}
}
else if ((fovfl & 0x40000000) != 0)
{
if ((fovfl & 0x3FFFFFFC) != 0)
{
fmant++;
}
}
FLOAT_TO_INTBITS (result) = fmant;
}
else
{
result = (KFloat) dresult;
}
}
/* Don't go straight to zero as the fact that x*0 = 0 independent
* of x might cause the algorithm to produce an incorrect result.
* Instead try the min value first and let it fall to zero if need
* be.
*/
if (e <= -309 || FLOAT_TO_INTBITS (result) == 0)
FLOAT_TO_INTBITS (result) = MINIMUM_INTBITS;
return floatAlgorithm (f, length, e, result);
}
#if defined(WIN32)
/* disable global optimizations on the microsoft compiler for the
* floatAlgorithm function otherwise it won't properly compile */
#pragma optimize("g",off)
#endif
/* The algorithm for the function floatAlgorithm() below can be found
* in:
*
* "How to Read Floating-Point Numbers Accurately", William D.
* Clinger, Proceedings of the ACM SIGPLAN '90 Conference on
* Programming Language Design and Implementation, June 20-22,
* 1990, pp. 92-101.
*
* There is a possibility that the function will end up in an endless
* loop if the given approximating floating-point number (a very small
* floating-point whose value is very close to zero) straddles between
* two approximating integer values. We modified the algorithm slightly
* to detect the case where it oscillates back and forth between
* incrementing and decrementing the floating-point approximation. It
* is currently set such that if the oscillation occurs more than twice
* then return the original approximation.
*/
KFloat
floatAlgorithm (U_64 * f, IDATA length, KInt e, KFloat z)
{
U_64 m;
IDATA k, comparison, comparison2;
U_64 *x, *y, *D, *D2;
IDATA xLength, yLength, DLength, D2Length;
IDATA decApproxCount, incApproxCount;
//PORT_ACCESS_FROM_ENV (env);
x = y = D = D2 = 0;
xLength = yLength = DLength = D2Length = 0;
decApproxCount = incApproxCount = 0;
do
{
m = floatMantissa (z);
k = floatExponent (z);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
if (e >= 0 && k >= 0)
{
xLength = sizeOfTenToTheE (e) + length;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
yLength = (k >> 6) + 2;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
simpleShiftLeftHighPrecision (y, yLength, k);
}
else if (e >= 0)
{
xLength = sizeOfTenToTheE (e) + length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
timesTenToTheEHighPrecision (x, xLength, e);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = 1;
allocateU64 (y, 1);
*y = m;
}
else if (k >= 0)
{
xLength = length;
x = f;
yLength = sizeOfTenToTheE (-e) + 2 + (k >> 6);
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
simpleShiftLeftHighPrecision (y, yLength, k);
}
else
{
xLength = length + ((-k) >> 6) + 1;
allocateU64 (x, xLength);
memset (x + length, 0, sizeof (U_64) * (xLength - length));
memcpy (x, f, sizeof (U_64) * length);
simpleShiftLeftHighPrecision (x, xLength, -k);
yLength = sizeOfTenToTheE (-e) + 1;
allocateU64 (y, yLength);
memset (y + 1, 0, sizeof (U_64) * (yLength - 1));
*y = m;
timesTenToTheEHighPrecision (y, yLength, -e);
}
comparison = compareHighPrecision (x, xLength, y, yLength);
if (comparison > 0)
{ /* x > y */
DLength = xLength;
allocateU64 (D, DLength);
memcpy (D, x, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, y, yLength);
}
else if (comparison)
{ /* y > x */
DLength = yLength;
allocateU64 (D, DLength);
memcpy (D, y, DLength * sizeof (U_64));
subtractHighPrecision (D, DLength, x, xLength);
}
else
{ /* y == x */
DLength = 1;
allocateU64 (D, 1);
*D = 0;
}
D2Length = DLength + 1;
allocateU64 (D2, D2Length);
m <<= 1;
multiplyHighPrecision (D, DLength, &m, 1, D2, D2Length);
m >>= 1;
comparison2 = compareHighPrecision (D2, D2Length, y, yLength);
if (comparison2 < 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
simpleShiftLeftHighPrecision (D2, D2Length, 1);
if (compareHighPrecision (D2, D2Length, y, yLength) > 0)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else
{
break;
}
}
else if (comparison2 == 0)
{
if ((m & 1) == 0)
{
if (comparison < 0 && m == NORMAL_MASK)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
else
{
break;
}
}
else if (comparison < 0)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
break;
}
else
{
INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
break;
}
}
else if (comparison < 0)
{
DECREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
else
{
if (FLOAT_TO_INTBITS (z) == EXPONENT_MASK)
break;
INCREMENT_FLOAT (z, decApproxCount, incApproxCount);
}
}
while (1);
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
return z;
OutOfMemory:
if (x && x != f)
//jclmem_free_memory (env, x);
release(x);
release (y);
release (D);
release (D2);
FLOAT_TO_INTBITS (z) = -2;
return z;
}
#if defined(WIN32)
#pragma optimize("",on) /*restore optimizations */
#endif
extern "C" KFloat
Kotlin_native_FloatingPointParser_parseFloatImpl(KString s, KInt e)
{
const KChar* utf16 = CharArrayAddressOfElementAt(s, 0);
KStdString utf8;
utf8.reserve(s->count_);
TRY_CATCH(utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)),
utf8::unchecked::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)),
/* Illegal UTF-16 string. */ ThrowNumberFormatException());
const char *str = utf8.c_str();
auto flt = createFloat(str, e);
if (((I_32) FLOAT_TO_INTBITS (flt)) >= 0) {
return flt;
} else if (((I_32) FLOAT_TO_INTBITS (flt)) == (I_32) - 1) {
/* NumberFormatException */
ThrowNumberFormatException();
} else {
/* OutOfMemoryError */
ThrowOutOfMemoryError();
}
return 0.0f;
}
@@ -0,0 +1,523 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#if !defined(hycomp_h)
#define hycomp_h
// TODO: Move to settings
#define MACOSX
/**
* USE_PROTOTYPES: Use full ANSI prototypes.
*
* CLOCK_PRIMS: We want the timer/clock prims to be used
*
* LITTLE_ENDIAN: This is for the intel machines or other
* little endian processors. Defaults to big endian.
*
* NO_LVALUE_CASTING: This is for compilers that don't like the left side
* of assigns to be cast. It hacks around to do the
* right thing.
*
* ATOMIC_FLOAT_ACCESS: So that float operations will work.
*
* LINKED_USER_PRIMITIVES: Indicates that user primitives are statically linked
* with the VM executeable.
*
* OLD_SPACE_SIZE_DIFF: The 68k uses a different amount of old space.
* This "legitimizes" the change.
*
* SIMPLE_SIGNAL: For machines that don't use real signals in C.
* (eg: PC, 68k)
*
* OS_NAME_LOOKUP: Use nlist to lookup user primitive addresses.
*
* VMCALL: Tag for all functions called by the VM.
*
* VMAPICALL: Tag for all functions called via the PlatformFunction
* callWith: mechanism.
*
* SYS_FLOAT: For some math functions where extended types (80 or 96 bits) are returned
* Most platforms return as a double
*
* FLOAT_EXTENDED: If defined, the type name for extended precision floats.
*
* PLATFORM_IS_ASCII: Must be defined if the platform is ASCII
*
* EXE_EXTENSION_CHAR: the executable has a delimiter that we want to stop at as part of argv[0].
*/
/**
* By default order doubles in the native (that is big/little endian) ordering.
*/
#define HY_PLATFORM_DOUBLE_ORDER
/**
* Define common types:
* <ul>
* <li><code>U_32 / I_32</code> - unsigned/signed 32 bits</li>
* <li><code>U_16 / I_16</code> - unsigned/signed 16 bits</li>
* <li><code>U_8 / I_8</code> - unsigned/signed 8 bits (bytes -- not to be
* confused with char)</li>
* </ul>
*/
typedef int I_32;
typedef short I_16;
typedef signed char I_8; /* chars can be unsigned */
typedef unsigned int U_32;
typedef unsigned short U_16;
typedef unsigned char U_8;
/**
* Define platform specific types:
* <ul>
* <li><code>U_64 / I_64</code> - unsigned/signed 64 bits</li>
* </ul>
*/
#if defined(LINUX) || defined(FREEBSD) || defined(AIX) || defined(MACOSX)
#define DATA_TYPES_DEFINED
/* NOTE: Linux supports different processors -- do not assume 386 */
#if defined(HYX86_64) || defined(HYIA64) || defined(HYPPC64) || defined(HYS390X)
typedef unsigned long int U_64; /* 64bits */
typedef long int I_64;
#define TOC_UNWRAP_ADDRESS(wrappedPointer) ((void *) (wrappedPointer)[0])
#define TOC_STORE_TOC(dest,wrappedPointer) (dest = ((UDATA*)wrappedPointer)[1])
#define HY_WORD64
#else
typedef long long I_64;
typedef unsigned long long U_64;
#endif
#if defined(HYS390X) || defined(HYS390) || defined(HYPPC64) || defined(HYPPC32) || defined(__MIPSEB__)
#define HY_BIG_ENDIAN
#else
#define HY_LITTLE_ENDIAN
#endif
#if defined(HYPPC32) && defined(LINUX)
#define VA_PTR(valist) (&valist[0])
#endif
typedef double SYS_FLOAT;
#define HYCONST64(x) x##LL
#define NO_LVALUE_CASTING
#define FLOAT_EXTENDED long double
#define PLATFORM_IS_ASCII
#define PLATFORM_LINE_DELIMITER "\012"
#define DIR_SEPARATOR '/'
#define DIR_SEPARATOR_STR "/"
#define PATH_SEPARATOR ':'
#define PATH_SEPARATOR_STR ":"
#if defined(AIX)
#define LIBPATH_ENV_VAR "LIBPATH"
#else
#if defined(MACOSX)
#define LIBPATH_ENV_VAR "DYLD_LIBRARY_PATH"
#else
#define LIBPATH_ENV_VAR "LD_LIBRARY_PATH"
#endif
#endif
#if defined(MACOSX)
#define PLATFORM_DLL_EXTENSION ".dylib"
#else
#define PLATFORM_DLL_EXTENSION ".so"
#endif
/**
* No priorities on Linux
*/
#define HY_PRIORITY_MAP {0,0,0,0,0,0,0,0,0,0,0,0}
typedef U_32 BOOLEAN;
#endif
/* Win32 - Windows 3.1 & NT using Win32 */
#if defined(WIN32)
#define HY_LITTLE_ENDIAN
/* Define 64-bit integers for Windows */
typedef __int64 I_64;
typedef unsigned __int64 U_64;
typedef double SYS_FLOAT;
#define NO_LVALUE_CASTING
#define VMAPICALL _stdcall
#define VMCALL _cdecl
#define EXE_EXTENSION_CHAR '.'
#define DIR_SEPARATOR '\\'
#define DIR_SEPARATOR_STR "\\"
#define PATH_SEPARATOR ';'
#define PATH_SEPARATOR_STR ";"
#define LIBPATH_ENV_VAR "PATH"
/* Modifications for the Alpha running WIN-NT */
#if defined(_ALPHA_)
#undef small /* defined as char in rpcndr.h */
typedef double FLOAT_EXTENDED;
#endif
#define HY_PRIORITY_MAP { \
THREAD_PRIORITY_IDLE, /* 0 */\
THREAD_PRIORITY_LOWEST, /* 1 */\
THREAD_PRIORITY_BELOW_NORMAL, /* 2 */\
THREAD_PRIORITY_BELOW_NORMAL, /* 3 */\
THREAD_PRIORITY_BELOW_NORMAL, /* 4 */\
THREAD_PRIORITY_NORMAL, /* 5 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 6 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 7 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 8 */\
THREAD_PRIORITY_ABOVE_NORMAL, /* 9 */\
THREAD_PRIORITY_HIGHEST, /*10 */\
THREAD_PRIORITY_TIME_CRITICAL /*11 */}
#endif /* defined(WIN32) */
#if defined(ZOS)
#define HY_BIG_ENDIAN
#define DATA_TYPES_DEFINED
typedef unsigned int BOOLEAN;
#if defined (HYS390X)
typedef unsigned long U_64;
typedef long I_64;
#else
typedef signed long long I_64;
typedef unsigned long long U_64;
#endif
typedef double SYS_FLOAT;
#define HYCONST64(x) x##LL
#define NO_LVALUE_CASTING
#define PLATFORM_LINE_DELIMITER "\012"
#define DIR_SEPARATOR '/'
#define DIR_SEPARATOR_STR "/"
#define PATH_SEPARATOR ':'
#define PATH_SEPARATOR_STR ":"
#define LIBPATH_ENV_VAR "LIBPATH"
#define VA_PTR(valist) (&valist[0])
typedef struct {
#if !defined(HYS390X)
char stuff[16];
#endif
char *ada;
void (*rawFnAddress)();
} HyFunctionDescriptor_T;
#define TOC_UNWRAP_ADDRESS(wrappedPointer) (((HyFunctionDescriptor_T *) (wrappedPointer))->rawFnAddress)
#define PLATFORM_DLL_EXTENSION ".so"
#ifdef HYS390X
#ifndef HY_WORD64
#define HY_WORD64
#endif /* ifndef HY_WORD64 */
#endif /* HYS390X */
#endif /* ZOS */
#if !defined(VMCALL)
#define VMCALL
#define VMAPICALL
#endif
#define PVMCALL VMCALL *
#define GLOBAL_DATA(symbol) ((void*)&(symbol))
#define GLOBAL_TABLE(symbol) GLOBAL_DATA(symbol)
/**
* Define platform specific types:
* <ul>
* <li><code>UDATA</code> - unsigned data, can be used as an integer or
* pointer storage</li>
* <li><code>IDATA</code> - signed data, can be used as an integer or
* pointer storage</li>
* </ul>
*/
/* FIXME: POINTER64 */
#if defined(HYX86_64) || defined(HYIA64) || defined(HYPPC64) || defined(HYS390X) || defined(POINTER64)
typedef I_64 IDATA;
typedef U_64 UDATA;
#else /* this is default for non-64bit systems */
typedef I_32 IDATA;
typedef U_32 UDATA;
#endif /* defined(HYX86_64) */
#if !defined(DATA_TYPES_DEFINED)
/* no generic U_64 or I_64 */
/* don't typedef BOOLEAN since it's already def'ed on Win32 */
#define BOOLEAN UDATA
#ifndef HY_BIG_ENDIAN
#define HY_LITTLE_ENDIAN
#endif
#endif
#if !defined(HYCONST64)
#define HYCONST64(x) x##L
#endif
#if !defined(HY_DEFAULT_SCHED)
/**
* By default, pthreads platforms use the <code>SCHED_OTHER</code> thread
* scheduling policy.
*/
#define HY_DEFAULT_SCHED SCHED_OTHER
#endif
#if !defined(HY_PRIORITY_MAP)
/**
* If no priority map if provided, priorities will be determined
* algorithmically.
*/
#endif
#if !defined(FALSE)
#define FALSE ((BOOLEAN) 0)
#if !defined(TRUE)
#define TRUE ((BOOLEAN) (!FALSE))
#endif
#endif
#if !defined(NULL)
#if defined(__cplusplus)
#define NULL (0)
#else
#define NULL ((void *)0)
#endif
#endif
#define USE_PROTOTYPES
#if defined(USE_PROTOTYPES)
#define PROTOTYPE(x) x
#define VARARGS , ...
#else
#define PROTOTYPE(x) ()
#define VARARGS
#endif
/**
* Assign the default line delimiter, if it was not set.
*/
#if !defined(PLATFORM_LINE_DELIMITER)
#define PLATFORM_LINE_DELIMITER "\015\012"
#endif
/**
* Set the max path length, if it was not set.
*/
#if !defined(MAX_IMAGE_PATH_LENGTH)
#define MAX_IMAGE_PATH_LENGTH (2048)
#endif
typedef double ESDOUBLE;
typedef float ESSINGLE;
/**
* Helpers for U_64s.
*/
#define CLEAR_U64(u64) (u64 = (U_64)0)
#define LOW_LONG(l) (*((U_32 *) &(l)))
#define HIGH_LONG(l) (*(((U_32 *) &(l)) + 1))
#define I8(x) ((I_8) (x))
#define I8P(x) ((I_8 *) (x))
#define U16(x) ((U_16) (x))
#define I16(x) ((I_16) (x))
#define I16P(x) ((I_16 *) (x))
#define U32(x) ((U_32) (x))
#define I32(x) ((I_32) (x))
#define I32P(x) ((I_32 *) (x))
#define U16P(x) ((U_16 *) (x))
#define U32P(x) ((U_32 *) (x))
#define OBJP(x) ((HyObject *) (x))
#define OBJPP(x) ((HyObject **) (x))
#define OBJPPP(x) ((HyObject ***) (x))
#define CLASSP(x) ((Class *) (x))
#define CLASSPP(x) ((Class **) (x))
#define BYTEP(x) ((BYTE *) (x))
/**
* Test - was conflicting with OS2.h
*/
#define ESCHAR(x) ((CHARACTER) (x))
#define FLT(x) ((FLOAT) x)
#define FLTP(x) ((FLOAT *) (x))
#if defined(NO_LVALUE_CASTING)
#define LI8(x) (*((I_8 *) &(x)))
#define LI8P(x) (*((I_8 **) &(x)))
#define LU16(x) (*((U_16 *) &(x)))
#define LI16(x) (*((I_16 *) &(x)))
#define LU32(x) (*((U_32 *) &(x)))
#define LI32(x) (*((I_32 *) &(x)))
#define LI32P(x) (*((I_32 **) &(x)))
#define LU16P(x) (*((U_16 **) &(x)))
#define LU32P(x) (*((U_32 **) &(x)))
#define LOBJP(x) (*((HyObject **) &(x)))
#define LOBJPP(x) (*((HyObject ***) &(x)))
#define LOBJPPP(x) (*((HyObject ****) &(x))
#define LCLASSP(x) (*((Class **) &(x)))
#define LBYTEP(x) (*((BYTE **) &(x)))
#define LCHAR(x) (*((CHARACTER) &(x)))
#define LFLT(x) (*((FLOAT) &x))
#define LFLTP(x) (*((FLOAT *) &(x)))
#else
#define LI8(x) I8((x))
#define LI8P(x) I8P((x))
#define LU16(x) U16((x))
#define LI16(x) I16((x))
#define LU32(x) U32((x))
#define LI32(x) I32((x))
#define LI32P(x) I32P((x))
#define LU16P(x) U16P((x))
#define LU32P(x) U32P((x))
#define LOBJP(x) OBJP((x))
#define LOBJPP(x) OBJPP((x))
#define LOBJPPP(x) OBJPPP((x))
#define LIOBJP(x) IOBJP((x))
#define LCLASSP(x) CLASSP((x))
#define LBYTEP(x) BYTEP((x))
#define LCHAR(x) CHAR((x))
#define LFLT(x) FLT((x))
#define LFLTP(x) FLTP((x))
#endif
/**
* Macros for converting between words and longs and accessing bits.
*/
#define HIGH_WORD(x) U16(U32((x)) >> 16)
#define LOW_WORD(x) U16(U32((x)) & 0xFFFF)
#define LOW_BIT(o) (U32((o)) & 1)
#define LOW_2_BITS(o) (U32((o)) & 3)
#define LOW_3_BITS(o) (U32((o)) & 7)
#define LOW_4_BITS(o) (U32((o)) & 15)
#define MAKE_32(h, l) ((U32((h)) << 16) | U32((l)))
#define MAKE_64(h, l) ((((I_64)(h)) << 32) | (l))
#if defined(__cplusplus)
#define HY_CFUNC "C"
#define HY_CDATA "C"
#else
#define HY_CFUNC
#define HY_CDATA
#endif
/**
* Macros for tagging functions which read/write the vm thread.
*/
#define READSVMTHREAD
#define WRITESVMTHREAD
#define REQUIRESSTACKFRAME
/**
* Macro for tagging functions, which never return.
*/
#if defined(__GNUC__)
/**
* On GCC, we can actually pass this information on to the compiler.
*/
#define NORETURN __attribute__((noreturn))
#else
#define NORETURN
#endif
/**
* On some systems va_list is an array type. This is probably in
* violation of the ANSI C spec, but it's not entirely clear. Because of
* this, we end up with an undesired extra level of indirection if we take
* the address of a va_list argument.
*
* To get it right, always use the VA_PTR macro
*/
#if !defined(VA_PTR)
#define VA_PTR(valist) (&valist)
#endif
#if !defined(TOC_UNWRAP_ADDRESS)
#define TOC_UNWRAP_ADDRESS(wrappedPointer) (wrappedPointer)
#endif
#if !defined(TOC_STORE_TOC)
#define TOC_STORE_TOC(dest,wrappedPointer)
#endif
/**
* Macros for accessing I_64 values.
*/
#if defined(ATOMIC_LONG_ACCESS)
#define PTR_LONG_STORE(dstPtr, aLongPtr) ((*U32P(dstPtr) = *U32P(aLongPtr)), (*(U32P(dstPtr)+1) = *(U32P(aLongPtr)+1)))
#define PTR_LONG_VALUE(dstPtr, aLongPtr) ((*U32P(aLongPtr) = *U32P(dstPtr)), (*(U32P(aLongPtr)+1) = *(U32P(dstPtr)+1)))
#else
#define PTR_LONG_STORE(dstPtr, aLongPtr) (*(dstPtr) = *(aLongPtr))
#define PTR_LONG_VALUE(dstPtr, aLongPtr) (*(aLongPtr) = *(dstPtr))
#endif
/**
* Macro used when declaring tables which require relocations.
*/
#if !defined(HYCONST_TABLE)
#define HYCONST_TABLE const
#endif
/**
* ANSI qsort is not always available.
*/
#if !defined(HY_SORT)
#define HY_SORT(base, nmemb, size, compare) qsort((base), (nmemb), (size), (compare))
#endif
/**
* Helper macros for storing/restoring pointers to jlong.
*/
#define jlong2addr(a, x) ((a *)((IDATA)(x)))
#define addr2jlong(x) ((jlong)((IDATA)(x)))
#endif /* hycomp_h */
@@ -0,0 +1,128 @@
musl as a whole is licensed under the following standard MIT license:
----------------------------------------------------------------------
Copyright © 2005-2014 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------
Authors/contributors include:
Anthony G. Basile
Arvid Picciani
Bobby Bingham
Boris Brezillon
Chris Spiegel
Emil Renner Berthing
Hiltjo Posthuma
Isaac Dunham
Jens Gustedt
Jeremy Huntwork
John Spencer
Justin Cormack
Luca Barbato
Luka Perkov
Michael Forney
Nicholas J. Kain
orc
Pascal Cuoq
Pierre Carrier
Rich Felker
Richard Pennington
Solar Designer
Strake
Szabolcs Nagy
Timo Teräs
Valentin Ochs
William Haddon
Portions of this software are derived from third-party works licensed
under terms compatible with the above MIT license:
The TRE regular expression implementation (src/regex/reg* and
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
under a 2-clause BSD license (license text in the source files). The
included version has been heavily modified by Rich Felker in 2012, in
the interests of size, simplicity, and namespace cleanliness.
Much of the math library code (src/math/* and src/complex/*) is
Copyright © 1993,2004 Sun Microsystems or
Copyright © 2003-2011 David Schultz or
Copyright © 2003-2009 Steven G. Kargl or
Copyright © 2003-2009 Bruce D. Evans or
Copyright © 2008 Stephen L. Moshier
and labelled as such in comments in the individual source files. All
have been licensed under extremely permissive terms.
The ARM memcpy code (src/string/armel/memcpy.s) is Copyright © 2008
The Android Open Source Project and is licensed under a two-clause BSD
license. It was taken from Bionic libc, used on Android.
The implementation of DES for crypt (src/misc/crypt_des.c) is
Copyright © 1994 David Burren. It is licensed under a BSD license.
The implementation of blowfish crypt (src/misc/crypt_blowfish.c) was
originally written by Solar Designer and placed into the public
domain. The code also comes with a fallback permissive license for use
in jurisdictions that may not recognize the public domain.
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
Valentin Ochs and is licensed under an MIT-style license.
The BSD PRNG implementation (src/prng/random.c) and XSI search API
(src/search/*.c) functions are Copyright © 2011 Szabolcs Nagy and
licensed under following terms: "Permission to use, copy, modify,
and/or distribute this code for any purpose with or without fee is
hereby granted. There is no warranty."
The x86_64 port was written by Nicholas J. Kain. Several files (crt)
were released into the public domain; others are licensed under the
standard MIT license terms at the top of this file. See individual
files for their copyright status.
The mips and microblaze ports were originally written by Richard
Pennington for use in the ellcc project. The original code was adapted
by Rich Felker for build system and code conventions during upstream
integration. It is licensed under the standard MIT terms.
The powerpc port was also originally written by Richard Pennington,
and later supplemented and integrated by John Spencer. It is licensed
under the standard MIT terms.
All other files which have no copyright comments are original works
produced specifically for use as part of this library, written either
by Rich Felker, the main author of the library, or by one or more
contibutors listed above. Details on authorship of individual files
can be found in the git version control history of the project. The
omission of copyright and license comments in each file is in the
interest of source tree size.
All public header files (include/* and arch/*/bits/*) should be
treated as Public Domain as they intentionally contain no content
which can be covered by copyright. Some source modules may fall in
this category as well. If you believe that a file is so trivial that
it should be in the Public Domain, please contact the authors and
request an explicit statement releasing it from copyright.
The following files are trivial, believed not to be copyrightable in
the first place, and hereby explicitly released to the Public Domain:
All public headers: include/*, arch/*/bits/*
Startup files: crt/*
@@ -0,0 +1,82 @@
#ifndef _ENDIAN_H
#define _ENDIAN_H
#include <features.h>
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#define __PDP_ENDIAN 3412
#if defined(__GNUC__) && defined(__BYTE_ORDER__)
#define __BYTE_ORDER __BYTE_ORDER__
#else
#include <bits/endian.h>
#endif
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define BIG_ENDIAN __BIG_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#define PDP_ENDIAN __PDP_ENDIAN
#define BYTE_ORDER __BYTE_ORDER
#include <stdint.h>
static __inline uint16_t __bswap16(uint16_t __x)
{
return __x<<8 | __x>>8;
}
static __inline uint32_t __bswap32(uint32_t __x)
{
return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24;
}
static __inline uint64_t __bswap64(uint64_t __x)
{
return __bswap32(__x)+0ULL<<32 | __bswap32(__x>>32);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htobe16(x) __bswap16(x)
#define be16toh(x) __bswap16(x)
#define betoh16(x) __bswap16(x)
#define htobe32(x) __bswap32(x)
#define be32toh(x) __bswap32(x)
#define betoh32(x) __bswap32(x)
#define htobe64(x) __bswap64(x)
#define be64toh(x) __bswap64(x)
#define betoh64(x) __bswap64(x)
#define htole16(x) (uint16_t)(x)
#define le16toh(x) (uint16_t)(x)
#define letoh16(x) (uint16_t)(x)
#define htole32(x) (uint32_t)(x)
#define le32toh(x) (uint32_t)(x)
#define letoh32(x) (uint32_t)(x)
#define htole64(x) (uint64_t)(x)
#define le64toh(x) (uint64_t)(x)
#define letoh64(x) (uint64_t)(x)
#else
#define htobe16(x) (uint16_t)(x)
#define be16toh(x) (uint16_t)(x)
#define betoh16(x) (uint16_t)(x)
#define htobe32(x) (uint32_t)(x)
#define be32toh(x) (uint32_t)(x)
#define betoh32(x) (uint32_t)(x)
#define htobe64(x) (uint64_t)(x)
#define be64toh(x) (uint64_t)(x)
#define betoh64(x) (uint64_t)(x)
#define htole16(x) __bswap16(x)
#define le16toh(x) __bswap16(x)
#define letoh16(x) __bswap16(x)
#define htole32(x) __bswap32(x)
#define le32toh(x) __bswap32(x)
#define letoh32(x) __bswap32(x)
#define htole64(x) __bswap64(x)
#define le64toh(x) __bswap64(x)
#define letoh64(x) __bswap64(x)
#endif
#endif
#endif
@@ -0,0 +1,75 @@
#include <math.h>
#include <stdint.h>
#ifdef KONAN_WASM
#include "Common.h"
#endif
#ifdef KONAN_WASM
RUNTIME_USED
#endif
double fmod(double x, double y)
{
union {double f; uint64_t i;} ux = {x}, uy = {y};
int ex = ux.i>>52 & 0x7ff;
int ey = uy.i>>52 & 0x7ff;
int sx = ux.i>>63;
uint64_t i;
/* in the followings uxi should be ux.i, but then gcc wrongly adds */
/* float load/store to inner loops ruining performance and code size */
uint64_t uxi = ux.i;
if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
return (x*y)/(x*y);
if (uxi<<1 <= uy.i<<1) {
if (uxi<<1 == uy.i<<1)
return 0*x;
return x;
}
/* normalize x and y */
if (!ex) {
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1ULL >> 12;
uxi |= 1ULL << 52;
}
if (!ey) {
for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1ULL >> 12;
uy.i |= 1ULL << 52;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 63 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
for (; uxi>>52 == 0; uxi <<= 1, ex--);
/* scale result */
if (ex > 0) {
uxi -= 1ULL << 52;
uxi |= (uint64_t)ex << 52;
} else {
uxi >>= -ex + 1;
}
uxi |= (uint64_t)sx << 63;
ux.i = uxi;
return ux.f;
}
@@ -0,0 +1,72 @@
#include <math.h>
#include <stdint.h>
#ifdef KONAN_WASM
#include "Common.h"
#endif
#ifdef KONAN_WASM
RUNTIME_USED
#endif
float fmodf(float x, float y)
{
union {float f; uint32_t i;} ux = {x}, uy = {y};
int ex = ux.i>>23 & 0xff;
int ey = uy.i>>23 & 0xff;
uint32_t sx = ux.i & 0x80000000;
uint32_t i;
uint32_t uxi = ux.i;
if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
return (x*y)/(x*y);
if (uxi<<1 <= uy.i<<1) {
if (uxi<<1 == uy.i<<1)
return 0*x;
return x;
}
/* normalize x and y */
if (!ex) {
for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1U >> 9;
uxi |= 1U << 23;
}
if (!ey) {
for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1U >> 9;
uy.i |= 1U << 23;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 31 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 31 == 0) {
if (i == 0)
return 0*x;
uxi = i;
}
for (; uxi>>23 == 0; uxi <<= 1, ex--);
/* scale result up */
if (ex > 0) {
uxi -= 1U << 23;
uxi |= (uint32_t)ex << 23;
} else {
uxi >>= -ex + 1;
}
uxi |= sx;
ux.i = uxi;
return ux.f;
}
@@ -0,0 +1,163 @@
/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
#ifndef _LIBM_H
#define _LIBM_H
#include <stdint.h>
#include <float.h>
#include <math.h>
//#include "endian.h"
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
union ldshape {
long double f;
struct {
uint64_t m;
uint16_t se;
} i;
};
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
union ldshape {
long double f;
struct {
uint64_t lo;
uint32_t mid;
uint16_t top;
uint16_t se;
} i;
struct {
uint64_t lo;
uint64_t hi;
} i2;
};
#else
#error Unsupported long double representation
#endif
#ifdef __EMSCRIPTEN__
/*
* asm.js doesn't have user-accessible floating point exceptions, so there's
* no point in trying to force expression evaluations to produce them.
*/
#define FORCE_EVAL(x)
#else
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
volatile float __x; \
__x = (x); \
} else if (sizeof(x) == sizeof(double)) { \
volatile double __x; \
__x = (x); \
} else { \
volatile long double __x; \
__x = (x); \
} \
} while(0)
#endif
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS(hi,lo,d) \
do { \
union {double f; uint64_t i;} __u; \
__u.f = (d); \
(hi) = __u.i >> 32; \
(lo) = (uint32_t)__u.i; \
} while (0)
/* Get the more significant 32 bit int from a double. */
#define GET_HIGH_WORD(hi,d) \
do { \
union {double f; uint64_t i;} __u; \
__u.f = (d); \
(hi) = __u.i >> 32; \
} while (0)
/* Get the less significant 32 bit int from a double. */
#define GET_LOW_WORD(lo,d) \
do { \
union {double f; uint64_t i;} __u; \
__u.f = (d); \
(lo) = (uint32_t)__u.i; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS(d,hi,lo) \
do { \
union {double f; uint64_t i;} __u; \
__u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \
(d) = __u.f; \
} while (0)
/* Set the more significant 32 bits of a double from an int. */
#define SET_HIGH_WORD(d,hi) \
do { \
union {double f; uint64_t i;} __u; \
__u.f = (d); \
__u.i &= 0xffffffff; \
__u.i |= (uint64_t)(hi) << 32; \
(d) = __u.f; \
} while (0)
/* Set the less significant 32 bits of a double from an int. */
#define SET_LOW_WORD(d,lo) \
do { \
union {double f; uint64_t i;} __u; \
__u.f = (d); \
__u.i &= 0xffffffff00000000ull; \
__u.i |= (uint32_t)(lo); \
(d) = __u.f; \
} while (0)
/* Get a 32 bit int from a float. */
#define GET_FLOAT_WORD(w,d) \
do { \
union {float f; uint32_t i;} __u; \
__u.f = (d); \
(w) = __u.i; \
} while (0)
/* Set a float from a 32 bit int. */
#define SET_FLOAT_WORD(d,w) \
do { \
union {float f; uint32_t i;} __u; \
__u.i = (w); \
(d) = __u.f; \
} while (0)
/* fdlibm kernel functions */
int __rem_pio2_large(double*,double*,int,int,int);
int __rem_pio2(double,double*);
double __sin(double,double,int);
double __cos(double,double);
double __tan(double,double,int);
double __expo2(double);
int __rem_pio2f(float,double*);
float __sindf(double);
float __cosdf(double);
float __tandf(double,int);
float __expo2f(float);
int __rem_pio2l(long double, long double *);
long double __sinl(long double, long double, int);
long double __cosl(long double, long double);
long double __tanl(long double, long double, int);
/* polynomial evaluation */
long double __polevll(long double, const long double *, int);
long double __p1evll(long double, const long double *, int);
#endif
@@ -0,0 +1,31 @@
#include <math.h>
#include <stdint.h>
double scalbn(double x, int n)
{
union {double f; uint64_t i;} u;
double_t y = x;
if (n > 1023) {
y *= 0x1p1023;
n -= 1023;
if (n > 1023) {
y *= 0x1p1023;
n -= 1023;
if (n > 1023)
n = 1023;
}
} else if (n < -1022) {
y *= 0x1p-1022;
n += 1022;
if (n < -1022) {
y *= 0x1p-1022;
n += 1022;
if (n < -1022)
n = -1022;
}
}
u.i = (uint64_t)(0x3ff+n)<<52;
x = y * u.f;
return x;
}
@@ -0,0 +1,9 @@
Patrick Powell <papowell@astart.com>
Brandon Long <blong@fiction.net>
Thomas Roessler <roessler@does-not-exist.org>
Michael Elkins <me@mutt.org>
Andrew Tridgell <tridge@samba.org>
Russ Allbery <rra@stanford.edu>
Hrvoje Niksic <hniksic@xemacs.org>
Damien Miller <djm@mindrot.org>
Holger Weiss <holger@jhweiss.de>
@@ -0,0 +1,3 @@
UNLESS SPECIFIED OTHERWISE IN THE INDIVIDUAL SOURCE FILES INCLUDED WITH
THIS PACKAGE, they may freely be used, modified and/or redistributed for
any purpose.
File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "utf8/unchecked.h"
#include "utf8/with_replacement.h"
#if !KONAN_NO_EXCEPTIONS
#include "utf8/checked.h"
#endif
#endif // header guard
@@ -0,0 +1,341 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t cp) : cp(cp) {}
virtual const char* what() const throw() { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const throw() { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const throw() { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const throw() { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
throw not_enough_room();
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
/// Deprecated in versions that include "prior"
template <typename octet_iterator>
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
{
octet_iterator end = it;
while (utf8::internal::is_trail(*(--it)))
if (it == pass_start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
octet_iterator temp = it;
return utf8::next(temp, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
for (distance_type i = 0; i < n; ++i)
utf8::next(it, end);
}
/**
* Calculates a count of characters needed to represent the string from first to last in UTF-16
* taking into account surrogate symbols. Throws an exception if the input is invalid.
*/
template<typename octet_iterator>
uint32_t utf16_length(octet_iterator first, octet_iterator last) {
uint32_t dist = 0;
while(first < last) {
uint32_t cp = utf8::next(first, last);
dist += (cp > 0xffff) ? 2 : 1;
}
return dist;
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start != end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start != end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& range_start,
const octet_iterator& range_end) :
it(octet_it), range_start(range_start), range_end(range_end)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#endif //header guard
@@ -0,0 +1,340 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_out_of_unicode_domain(u32 cp)
{
return cp > CODE_POINT_MAX;
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (!utf8::internal::is_out_of_unicode_domain(cp) && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
#define UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(CP, LENGTH) {if (utf8::internal::is_overlong_sequence(CP, LENGTH)) return OVERLONG_SEQUENCE;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, const octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, const octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 2)
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, const octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
if (utf8::internal::is_surrogate(code_point))
return INVALID_CODE_POINT;
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 3)
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, const octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
if (utf8::internal::is_out_of_unicode_domain(code_point))
return INVALID_CODE_POINT;
UTF8_CPP_RETURN_ON_OVERLONG_SEQUENCE(code_point, 4)
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, const octet_iterator end, uint32_t& code_point)
{
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded.
code_point = cp;
++it;
} else {
// Failure branch - restore the original value of the iterator
it = original_it;
}
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
//Deprecated in release 2.3
template <typename octet_iterator>
inline bool is_bom (octet_iterator it)
{
return (
(utf8::internal::mask8(*it++)) == bom[0] &&
(utf8::internal::mask8(*it++)) == bom[1] &&
(utf8::internal::mask8(*it)) == bom[2]
);
}
} // namespace utf8
#endif // header guard
@@ -0,0 +1,242 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
namespace utf8
{
namespace unchecked
{
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it)
{
uint32_t cp = utf8::internal::mask8(*it);
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
switch (length) {
case 1:
break;
case 2:
it++;
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
break;
case 3:
++it;
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
++it;
cp += (*it) & 0x3f;
break;
case 4:
++it;
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
++it;
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
++it;
cp += (*it) & 0x3f;
break;
}
++it;
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it)
{
return utf8::unchecked::next(it);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it)
{
while (utf8::internal::is_trail(*(--it))) ;
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
template <typename octet_iterator>
inline uint32_t previous(octet_iterator& it)
{
return utf8::unchecked::prior(it);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n)
{
for (distance_type i = 0; i < n; ++i)
utf8::unchecked::next(it);
}
/**
* Calculates a count of characters needed to represent the string from first to last in UTF-16
* taking into account surrogate symbols. Doesn't validate the input.
*/
template<typename octet_iterator>
uint32_t utf16_length(octet_iterator first, const octet_iterator last) {
uint32_t dist = 0;
while (first < last) {
uint32_t cp = utf8::unchecked::next(first);
dist += (cp > 0xffff) ? 2 : 1;
}
return dist;
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::unchecked::next(first);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, const u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
}
result = utf8::unchecked::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, const octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::unchecked::next(start);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::unchecked::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::unchecked::next(start);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
bool operator == (const iterator& rhs) const
{
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
::std::advance(it, utf8::internal::sequence_length(it));
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
::std::advance(it, utf8::internal::sequence_length(it));
return temp;
}
iterator& operator -- ()
{
utf8::unchecked::prior(it);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::unchecked::prior(it);
return temp;
}
}; // class iterator
} // namespace utf8::unchecked
} // namespace utf8
#endif // header guard
@@ -0,0 +1,148 @@
/*
* 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 UTF_FOR_CPP_WITH_REPLACEMENT_H
#define UTF_FOR_CPP_WITH_REPLACEMENT_H
#include "core.h"
#include "unchecked.h"
namespace utf8 {
namespace with_replacement {
constexpr uint32_t default_replacement = 0xfffd;
/*
* Returns the next codepoint replacing any invalid sequence with the replacement codepoint.
*/
template<typename octet_iterator>
uint32_t next(octet_iterator &it, const octet_iterator end, uint32_t replacement) {
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
return cp;
case internal::INVALID_LEAD :
case internal::INVALID_CODE_POINT :
case internal::OVERLONG_SEQUENCE :
it++;
return replacement;
case internal::NOT_ENOUGH_ROOM :
case internal::INCOMPLETE_SEQUENCE :
// The whole incomplete sequence is replaced with one replacement codepoint.
for (it++; it < end && utf8::internal::is_trail(*it); it++);
return replacement;
}
}
// Library API
/**
* Calculates a count of characters needed to represent the string from first to last in UTF-16
* taking into account surrogate symbols and invalid sequences.
* Assumes that all invalid sequences in the input will be replaced with `replacement`
* so each invalid sequence increases the result by 1 or 2 depending on `replacement`.
*/
template<typename octet_iterator>
uint32_t utf16_length(octet_iterator first,
const octet_iterator last,
const uint32_t replacement = default_replacement) {
uint32_t dist = 0;
while (first < last) {
uint32_t cp = next(first, last, replacement);
dist += (cp > 0xffff) ? 2 : 1;
}
return dist;
}
template<typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance(octet_iterator first, const octet_iterator last) {
typename std::iterator_traits<octet_iterator>::difference_type dist;
uint32_t unused = 0;
for (dist = 0; first < last; dist++) {
next(first, last, unused);
}
return dist;
}
template<typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8(u16bit_iterator start,
const u16bit_iterator end,
octet_iterator result,
const uint32_t replacement) {
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Process surrogates.
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start);
if (utf8::internal::is_trail_surrogate(trail_surrogate)) {
// Valid surrogate pair.
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
start++;
} else {
cp = replacement; // Invalid input: lone lead surrogate.
}
} else {
cp = replacement; // Invalid input: lone lead surrogate at the end of input.
}
} else if (utf8::internal::is_trail_surrogate(cp)) {
cp = replacement; // Invalid input: lone trail surrogate
}
result = utf8::unchecked::append(cp, result);
}
return result;
}
template<typename u16bit_iterator, typename octet_iterator>
inline octet_iterator utf16to8(u16bit_iterator start,
const u16bit_iterator end,
octet_iterator result) {
return utf16to8(start, end, result, default_replacement);
}
template<typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16(octet_iterator start,
const octet_iterator end,
u16bit_iterator result,
const uint32_t replacement) {
while (start != end) {
// The `next` method takes care about replacing invalid sequences.
uint32_t cp = next(start, end, replacement);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
} else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template<typename u16bit_iterator, typename octet_iterator>
inline u16bit_iterator utf8to16(octet_iterator start,
const octet_iterator end,
u16bit_iterator result) {
return utf8to16(start, end, result, default_replacement);
}
} // namespace with_replacement
} // namespace utf8
#endif // UTF_FOR_CPP_WITH_REPLACEMENT_H