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:
@@ -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,
|
||||
¤tUnhandledExceptionHook, currentUnhandledExceptionHook, hook, ¤tUnhandledExceptionHookLock,
|
||||
¤tUnhandledExceptionHookCookie);
|
||||
}
|
||||
|
||||
void OnUnhandledException(KRef throwable) {
|
||||
ObjHolder handlerHolder;
|
||||
auto* handler = SwapHeapRefLocked(¤tUnhandledExceptionHook, currentUnhandledExceptionHook, nullptr,
|
||||
¤tUnhandledExceptionHookLock, ¤tUnhandledExceptionHookCookie, 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 = §ionHeaders[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
|
||||
@@ -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 = §ions[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"
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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"
|
||||
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user