Add Kotlin object inspection to simplify debugging (#763)
This commit is contained in:
+9
-5
@@ -211,6 +211,10 @@ internal class LinkStage(val context: Context) {
|
|||||||
private val emitted = context.bitcodeFileName
|
private val emitted = context.bitcodeFileName
|
||||||
private val libraries = context.config.libraries
|
private val libraries = context.config.libraries
|
||||||
|
|
||||||
|
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
|
||||||
|
addAll(elements.filter { !it.isEmpty() })
|
||||||
|
}
|
||||||
|
|
||||||
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
|
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
|
||||||
val tmpCombined = createTempFile("combined", ".o")
|
val tmpCombined = createTempFile("combined", ".o")
|
||||||
tmpCombined.deleteOnExit()
|
tmpCombined.deleteOnExit()
|
||||||
@@ -218,13 +222,13 @@ internal class LinkStage(val context: Context) {
|
|||||||
|
|
||||||
val tool = distribution.llvmLto
|
val tool = distribution.llvmLto
|
||||||
val command = mutableListOf(tool, "-o", combined)
|
val command = mutableListOf(tool, "-o", combined)
|
||||||
command.addAll(platform.llvmLtoFlags)
|
command.addNonEmpty(platform.llvmLtoFlags)
|
||||||
when {
|
when {
|
||||||
optimize -> command.addAll(platform.llvmLtoOptFlags)
|
optimize -> command.addNonEmpty(platform.llvmLtoOptFlags)
|
||||||
debug -> command.addAll(platform.llvmDebugOptFlags)
|
debug -> command.addNonEmpty(platform.llvmDebugOptFlags)
|
||||||
else -> command.addAll(platform.llvmLtoNooptFlags)
|
else -> command.addNonEmpty(platform.llvmLtoNooptFlags)
|
||||||
}
|
}
|
||||||
command.addAll(files)
|
command.addNonEmpty(files)
|
||||||
runTool(*command.toTypedArray())
|
runTool(*command.toTypedArray())
|
||||||
|
|
||||||
return combined
|
return combined
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ targetToolchain.osx = clang-llvm-3.9.0-darwin-macos
|
|||||||
arch.osx = x86_64
|
arch.osx = x86_64
|
||||||
targetSysRoot.osx = target-sysroot-1-darwin-macos
|
targetSysRoot.osx = target-sysroot-1-darwin-macos
|
||||||
libffiDir.osx = libffi-3.2.1-2-darwin-macos
|
libffiDir.osx = libffi-3.2.1-2-darwin-macos
|
||||||
llvmLtoFlags.osx = -exported-symbol=_Konan_main
|
llvmLtoFlags.osx =
|
||||||
llvmLtoOptFlags.osx = -O3 -function-sections
|
llvmLtoOptFlags.osx = -O3 -function-sections
|
||||||
llvmLtoNooptFlags.osx = -O1
|
llvmLtoNooptFlags.osx = -O1
|
||||||
linkerKonanFlags.osx = -lc++
|
linkerKonanFlags.osx = -lc++
|
||||||
@@ -55,7 +55,7 @@ arch.ios = arm64
|
|||||||
entrySelector.ios = -alias _Konan_main _main
|
entrySelector.ios = -alias _Konan_main _main
|
||||||
targetSysRoot.ios = target-sysroot-2-darwin-ios
|
targetSysRoot.ios = target-sysroot-2-darwin-ios
|
||||||
libffiDir.ios = libffi-3.2.1-2-darwin-ios
|
libffiDir.ios = libffi-3.2.1-2-darwin-ios
|
||||||
llvmLtoFlags.ios = -exported-symbol=_Konan_main
|
llvmLtoFlags.ios =
|
||||||
llvmLtoOptFlags.ios = -O3 -function-sections
|
llvmLtoOptFlags.ios = -O3 -function-sections
|
||||||
linkerDebugFlags.ios = -S
|
linkerDebugFlags.ios = -S
|
||||||
llvmLtoNooptFlags.ios = -O1
|
llvmLtoNooptFlags.ios = -O1
|
||||||
@@ -76,7 +76,7 @@ arch.ios_sim = x86_64
|
|||||||
entrySelector.ios_sim = -alias _Konan_main _main
|
entrySelector.ios_sim = -alias _Konan_main _main
|
||||||
targetSysRoot.ios_sim = target-sysroot-1-darwin-ios-sim
|
targetSysRoot.ios_sim = target-sysroot-1-darwin-ios-sim
|
||||||
libffiDir.ios_sim = libffi-3.2.1-2-darwin-ios-sim
|
libffiDir.ios_sim = libffi-3.2.1-2-darwin-ios-sim
|
||||||
llvmLtoFlags.ios_sim = -exported-symbol=_Konan_main
|
llvmLtoFlags.ios_sim =
|
||||||
llvmLtoOptFlags.ios_sim = -O3 -function-sections
|
llvmLtoOptFlags.ios_sim = -O3 -function-sections
|
||||||
llvmLtoNooptFlags.ios_sim = -O1
|
llvmLtoNooptFlags.ios_sim = -O1
|
||||||
linkerKonanFlags.ios_sim = -lc++
|
linkerKonanFlags.ios_sim = -lc++
|
||||||
@@ -97,7 +97,7 @@ targetSysRoot.linux = target-gcc-toolchain-3-linux-x86-64/x86_64-unknown-linux-g
|
|||||||
libffiDir.linux = libffi-3.2.1-2-linux-x86-64
|
libffiDir.linux = libffi-3.2.1-2-linux-x86-64
|
||||||
# targetSysroot-relative.
|
# targetSysroot-relative.
|
||||||
libGcc.linux = ../../lib/gcc/x86_64-unknown-linux-gnu/4.8.5
|
libGcc.linux = ../../lib/gcc/x86_64-unknown-linux-gnu/4.8.5
|
||||||
llvmLtoFlags.linux = -exported-symbol=Konan_main
|
llvmLtoFlags.linux =
|
||||||
llvmLtoOptFlags.linux = -O3 -function-sections
|
llvmLtoOptFlags.linux = -O3 -function-sections
|
||||||
llvmLtoNooptFlags.linux = -O1
|
llvmLtoNooptFlags.linux = -O1
|
||||||
llvmLlcFlags.linux = -march=x86-64
|
llvmLlcFlags.linux = -march=x86-64
|
||||||
@@ -132,7 +132,7 @@ libffiDir.raspberrypi = libffi-3.2.1-2-raspberrypi
|
|||||||
linkerKonanFlags.raspberrypi = -Bstatic -lstdc++ -Bdynamic -ldl -lm -lpthread
|
linkerKonanFlags.raspberrypi = -Bstatic -lstdc++ -Bdynamic -ldl -lm -lpthread
|
||||||
# targetSysroot-relative.
|
# targetSysroot-relative.
|
||||||
libGcc.raspberrypi = lib/gcc/arm-linux-gnueabihf/4.8.3
|
libGcc.raspberrypi = lib/gcc/arm-linux-gnueabihf/4.8.3
|
||||||
llvmLtoFlags.raspberrypi = -exported-symbol=Konan_main
|
llvmLtoFlags.raspberrypi =
|
||||||
llvmLtoOptFlags.raspberrypi = -O3 -function-sections
|
llvmLtoOptFlags.raspberrypi = -O3 -function-sections
|
||||||
llvmLtoNooptFlags.raspberrypi = -O1
|
llvmLtoNooptFlags.raspberrypi = -O1
|
||||||
dynamicLinker.raspberrypi = /lib/ld-linux-armhf.so.3
|
dynamicLinker.raspberrypi = /lib/ld-linux-armhf.so.3
|
||||||
@@ -159,7 +159,7 @@ dependencies.linux-android_arm32 = \
|
|||||||
|
|
||||||
quadruple.android_arm32 = arm-linux-androideabi
|
quadruple.android_arm32 = arm-linux-androideabi
|
||||||
entrySelector.android_arm32 = -Wl,--defsym -Wl,main=Konan_main
|
entrySelector.android_arm32 = -Wl,--defsym -Wl,main=Konan_main
|
||||||
llvmLtoFlags.android_arm32 = -exported-symbol=Konan_main -emulated-tls -relocation-model=pic
|
llvmLtoFlags.android_arm32 = -emulated-tls -relocation-model=pic
|
||||||
llvmLtoOptFlags.android_arm32 = -O3 -function-sections
|
llvmLtoOptFlags.android_arm32 = -O3 -function-sections
|
||||||
linkerDebugFlags.android_arm32 = -Wl,-S
|
linkerDebugFlags.android_arm32 = -Wl,-S
|
||||||
llvmLtoNooptFlags.android_arm32 = -O1
|
llvmLtoNooptFlags.android_arm32 = -O1
|
||||||
@@ -184,7 +184,7 @@ dependencies.linux-android_arm64 = \
|
|||||||
|
|
||||||
quadruple.android_arm64 = aarch64-linux-android
|
quadruple.android_arm64 = aarch64-linux-android
|
||||||
entrySelector.android_arm64 = -Wl,--defsym -Wl,main=Konan_main
|
entrySelector.android_arm64 = -Wl,--defsym -Wl,main=Konan_main
|
||||||
llvmLtoFlags.android_arm64 = -exported-symbol=Konan_main -emulated-tls -relocation-model=pic
|
llvmLtoFlags.android_arm64 = -emulated-tls -relocation-model=pic
|
||||||
targetSysRoot.android_arm64 = target-sysroot-21-android_arm64
|
targetSysRoot.android_arm64 = target-sysroot-21-android_arm64
|
||||||
libffiDir.android_arm64 = libffi-3.2.1-2-android_arm64
|
libffiDir.android_arm64 = libffi-3.2.1-2-android_arm64
|
||||||
linkerKonanFlags.android_arm64 = -lm -latomic -lstdc++ -landroid
|
linkerKonanFlags.android_arm64 = -lm -latomic -lstdc++ -landroid
|
||||||
@@ -198,7 +198,7 @@ targetToolchain.mingw = msys2-mingw-w64-x86_64-gcc-6.3.0-clang-llvm-3.9.1-window
|
|||||||
quadruple.mingw = x86_64-w64-mingw32
|
quadruple.mingw = x86_64-w64-mingw32
|
||||||
targetSysRoot.mingw = msys2-mingw-w64-x86_64-gcc-6.3.0-clang-llvm-3.9.1-windows-x86-64
|
targetSysRoot.mingw = msys2-mingw-w64-x86_64-gcc-6.3.0-clang-llvm-3.9.1-windows-x86-64
|
||||||
libffiDir.mingw = libffi-3.2.1-mingw-w64-x86-64
|
libffiDir.mingw = libffi-3.2.1-mingw-w64-x86-64
|
||||||
llvmLtoFlags.mingw = -exported-symbol=Konan_main
|
llvmLtoFlags.mingw =
|
||||||
llvmLtoOptFlags.mingw = -O3 -function-sections
|
llvmLtoOptFlags.mingw = -O3 -function-sections
|
||||||
llvmLtoNooptFlags.mingw = -O1
|
llvmLtoNooptFlags.mingw = -O1
|
||||||
linkerDebugFlags.mingw = -Wl,-S
|
linkerDebugFlags.mingw = -Wl,-S
|
||||||
@@ -219,10 +219,11 @@ dependencies.osx-wasm32 = \
|
|||||||
|
|
||||||
quadruple.wasm32 = wasm32
|
quadruple.wasm32 = wasm32
|
||||||
entrySelector.wasm32 = -Wl,--defsym -Wl,main=Konan_main
|
entrySelector.wasm32 = -Wl,--defsym -Wl,main=Konan_main
|
||||||
llvmLtoFlags.wasm32 = -exported-symbol=Konan_main
|
llvmLtoFlags.wasm32 =
|
||||||
targetSysRoot.wasm32 = target-sysroot-1-wasm
|
targetSysRoot.wasm32 = target-sysroot-1-wasm
|
||||||
clangFlags.wasm32 = -O1 -fno-rtti -fno-exceptions \
|
clangFlags.wasm32 = -O1 -fno-rtti -fno-exceptions \
|
||||||
-D_LIBCPP_ABI_VERSION=2 -DKONAN_NO_FFI=1 -DKONAN_NO_THREADS=1 -DKONAN_NO_EXCEPTIONS=1 \
|
-D_LIBCPP_ABI_VERSION=2 -DKONAN_NO_FFI=1 -DKONAN_NO_THREADS=1 -DKONAN_NO_EXCEPTIONS=1 \
|
||||||
|
-DKONAN_NO_DEBUG_API=1 \
|
||||||
-nostdinc -Xclang -nobuiltininc -Xclang -nostdsysteminc \
|
-nostdinc -Xclang -nobuiltininc -Xclang -nostdsysteminc \
|
||||||
-Xclang -isystem<sysrootDir>/include/libcxx -Xclang -isystem<sysrootDir>/lib/libcxxabi/include \
|
-Xclang -isystem<sysrootDir>/include/libcxx -Xclang -isystem<sysrootDir>/lib/libcxxabi/include \
|
||||||
-Xclang -isystem<sysrootDir>/include/compat -Xclang -isystem<sysrootDir>/include/libc
|
-Xclang -isystem<sysrootDir>/include/compat -Xclang -isystem<sysrootDir>/include/libc
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ OBJ_GETTER(setupArgs, int argc, const char** argv) {
|
|||||||
//--- main --------------------------------------------------------------------//
|
//--- main --------------------------------------------------------------------//
|
||||||
extern "C" KInt Konan_start(const ObjHeader*);
|
extern "C" KInt Konan_start(const ObjHeader*);
|
||||||
|
|
||||||
extern "C" int Konan_main(int argc, const char** argv) {
|
extern "C" RUNTIME_USED int Konan_main(int argc, const char** argv) {
|
||||||
RuntimeState* state = InitRuntime();
|
RuntimeState* state = InitRuntime();
|
||||||
|
|
||||||
if (state == nullptr) {
|
if (state == nullptr) {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#define RUNTIME_NOTHROW __attribute__((nothrow))
|
#define RUNTIME_NOTHROW __attribute__((nothrow))
|
||||||
#define RUNTIME_CONST __attribute__((const))
|
#define RUNTIME_CONST __attribute__((const))
|
||||||
#define RUNTIME_PURE __attribute__((pure))
|
#define RUNTIME_PURE __attribute__((pure))
|
||||||
|
#define RUNTIME_USED __attribute__((used))
|
||||||
|
|
||||||
#if KONAN_NO_THREADS
|
#if KONAN_NO_THREADS
|
||||||
#define THREAD_LOCAL_VARIABLE
|
#define THREAD_LOCAL_VARIABLE
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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 "KDebug.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Assert.h"
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Natives.h"
|
||||||
|
#include "Porting.h"
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
|
#ifndef KONAN_NO_DEBUG_API
|
||||||
|
|
||||||
|
extern "C" OBJ_GETTER(KonanObjectToUtf8Array, KRef object);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
char debugBuffer[4096];
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// Buffer that can be used by debugger for inspections.
|
||||||
|
RUNTIME_USED char* Konan_DebugBuffer() {
|
||||||
|
return debugBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED int Konan_DebugBufferSize() {
|
||||||
|
return sizeof(debugBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auxilary function which can be called by developer/debugger to inspect an object.
|
||||||
|
RUNTIME_USED KInt Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, KInt bufferSize) {
|
||||||
|
ObjHolder stringHolder;
|
||||||
|
auto data = KonanObjectToUtf8Array(obj, stringHolder.slot())->array();
|
||||||
|
if (data == nullptr) return 0;
|
||||||
|
KInt toCopy = data->count_ > bufferSize - 1 ? bufferSize - 1 : data->count_;
|
||||||
|
::memcpy(buffer, ByteArrayAddressOfElementAt(data, 0), toCopy);
|
||||||
|
buffer[toCopy + 1] = '\0';
|
||||||
|
return toCopy + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED KInt Konan_DebugPrint(KRef obj) {
|
||||||
|
KInt size = Konan_DebugObjectToUtf8Array(obj, Konan_DebugBuffer(), Konan_DebugBufferSize());
|
||||||
|
if (size > 1)
|
||||||
|
konan::consoleWriteUtf8(Konan_DebugBuffer(), size - 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index) {
|
||||||
|
if (obj == nullptr || index < 0) return Konan_RuntimeType::INVALID;
|
||||||
|
auto typeInfo = obj->type_info();
|
||||||
|
if (typeInfo->instanceSize_ < 0) {
|
||||||
|
// Arrays.
|
||||||
|
if (index >= obj->array()->count_) return Konan_RuntimeType::INVALID;
|
||||||
|
if (typeInfo == theArrayTypeInfo) {
|
||||||
|
return Konan_RuntimeType::OBJECT;
|
||||||
|
}
|
||||||
|
// TODO: support other array types.
|
||||||
|
return Konan_RuntimeType::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: support primitive type fields as well!
|
||||||
|
if (index >= typeInfo->objOffsetsCount_) return Konan_RuntimeType::INVALID;
|
||||||
|
return Konan_RuntimeType::OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
|
||||||
|
if (obj == nullptr || index < 0) return nullptr;
|
||||||
|
auto typeInfo = obj->type_info();
|
||||||
|
if (typeInfo->instanceSize_ < 0) {
|
||||||
|
// Arrays.
|
||||||
|
if (index >= obj->array()->count_) return nullptr;
|
||||||
|
if (typeInfo == theArrayTypeInfo) {
|
||||||
|
return ArrayAddressOfElementAt(obj->array(), index);
|
||||||
|
}
|
||||||
|
// TODO: support other array types.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// TODO: support primitive type fields as well!
|
||||||
|
if (index >= typeInfo->objOffsetsCount_) return nullptr;
|
||||||
|
return reinterpret_cast<uint8_t*>(obj + 1) + typeInfo->objOffsets_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
#endif // !KONAN_NO_DEBUG_API
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
// Type for runtime representation of Konan object.
|
||||||
|
enum Konan_RuntimeType {
|
||||||
|
INVALID = 0,
|
||||||
|
OBJECT = 1,
|
||||||
|
INT8 = 2,
|
||||||
|
INT16 = 3,
|
||||||
|
INT32 = 4,
|
||||||
|
INT64 = 5,
|
||||||
|
FLOAT32 = 6,
|
||||||
|
FLOAT64 = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get memory buffer where debugger can put data in Konan app process.
|
||||||
|
RUNTIME_USED
|
||||||
|
char* Konan_DebugBuffer();
|
||||||
|
|
||||||
|
// Get size of memory buffer where debugger can put data in Konan app process.
|
||||||
|
RUNTIME_USED
|
||||||
|
int Konan_DebugBufferSize();
|
||||||
|
|
||||||
|
// Put string representation of an object to the provided buffer.
|
||||||
|
RUNTIME_USED
|
||||||
|
int Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int bufferSize);
|
||||||
|
|
||||||
|
// Print to console string representation of an object.
|
||||||
|
RUNTIME_USED
|
||||||
|
int Konan_DebugPrint(KRef obj);
|
||||||
|
|
||||||
|
// Compute type of field or an array element at the index, or 0, if incorrect,
|
||||||
|
// see Konan_RuntimeType.
|
||||||
|
// TODO: currently, only object fields are supported, will be fixed soon.
|
||||||
|
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index);
|
||||||
|
|
||||||
|
// Compute address of field or an array element at the index, or null, if incorrect.
|
||||||
|
// TODO: currently, only object fields are supported, will be fixed soon.
|
||||||
|
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !KONAN_NO_DEBUG_API
|
||||||
|
|
||||||
|
#endif // RUNTIME_KDEBUG_H
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef RUNTIME_STRING_H
|
#ifndef RUNTIME_KSTRING_H
|
||||||
#define RUNTIME_STRING_H
|
#define RUNTIME_KSTRING_H
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
@@ -52,4 +52,4 @@ int binarySearchRange(const T* array, int arrayLength, T needle) {
|
|||||||
return middle - (needle < value ? 1 : 0);
|
return middle - (needle < value ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RUNTIME_STRING_H
|
#endif // RUNTIME_KSTRING_H
|
||||||
|
|||||||
@@ -23,54 +23,60 @@
|
|||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
#include "KString.h"
|
#include "KString.h"
|
||||||
|
#include "Porting.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
char int_to_digit(uint32_t value) {
|
char int_to_digit(uint32_t value) {
|
||||||
if (value < 10) {
|
if (value < 10) {
|
||||||
return '0' + value;
|
return '0' + value;
|
||||||
} else {
|
} else {
|
||||||
return 'a' + (value - 10);
|
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");
|
|
||||||
}
|
|
||||||
char cstring[sizeof(T) * CHAR_BIT + 1];
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
char cstring[sizeof(T) * CHAR_BIT + 1];
|
||||||
|
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" {
|
extern "C" {
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) {
|
OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) {
|
||||||
char cstring[80];
|
char cstring[80];
|
||||||
snprintf(cstring, sizeof(cstring), "%s %p type %p",
|
if (IsArray(thiz)) {
|
||||||
IsArray(thiz) ? "array" : "object",
|
konan::snprintf(cstring, sizeof(cstring), "%d@%p: array of %d",
|
||||||
thiz, thiz->type_info_);
|
Kotlin_Any_hashCode(thiz), thiz->type_info_, thiz->array()->count_);
|
||||||
|
} else {
|
||||||
|
konan::snprintf(cstring, sizeof(cstring), "%d@%p: object",
|
||||||
|
Kotlin_Any_hashCode(thiz), thiz->type_info_);
|
||||||
|
}
|
||||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,21 +119,4 @@ OBJ_GETTER(Kotlin_Long_toStringRadix, KLong value, KInt radix) {
|
|||||||
RETURN_RESULT_OF(Kotlin_toStringRadix<KLong>, value, radix)
|
RETURN_RESULT_OF(Kotlin_toStringRadix<KLong>, value, radix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use David Gay's dtoa() here instead. It's *very* big and ugly.
|
|
||||||
OBJ_GETTER(Kotlin_Float_toString, KFloat value) {
|
|
||||||
char cstring[32];
|
|
||||||
snprintf(cstring, sizeof(cstring), "%G", value);
|
|
||||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_Double_toString, KDouble value) {
|
|
||||||
char cstring[32];
|
|
||||||
snprintf(cstring, sizeof(cstring), "%G", value);
|
|
||||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
|
||||||
}
|
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_Boolean_toString, KBoolean value) {
|
|
||||||
RETURN_RESULT_OF(CreateStringFromCString, value ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package konan.internal
|
||||||
|
|
||||||
|
import kotlin.text.toUtf8Array
|
||||||
|
|
||||||
|
// Called by debugger.
|
||||||
|
@ExportForCppRuntime
|
||||||
|
fun KonanObjectToUtf8Array(value: Any?): ByteArray {
|
||||||
|
val string = when (value) {
|
||||||
|
is Array<*> -> value.contentToString()
|
||||||
|
is CharArray -> value.contentToString()
|
||||||
|
is BooleanArray -> value.contentToString()
|
||||||
|
is ByteArray -> value.contentToString()
|
||||||
|
is ShortArray -> value.contentToString()
|
||||||
|
is IntArray -> value.contentToString()
|
||||||
|
is LongArray -> value.contentToString()
|
||||||
|
is FloatArray -> value.contentToString()
|
||||||
|
is DoubleArray -> value.contentToString()
|
||||||
|
else -> value.toString()
|
||||||
|
}
|
||||||
|
return toUtf8Array(string, 0, string.length)
|
||||||
|
}
|
||||||
@@ -54,10 +54,7 @@ public final class Boolean : Comparable<Boolean> {
|
|||||||
public override fun equals(other: Any?): Boolean =
|
public override fun equals(other: Any?): Boolean =
|
||||||
other is Boolean && konan.internal.areEqualByValue(this, other)
|
other is Boolean && konan.internal.areEqualByValue(this, other)
|
||||||
|
|
||||||
@SymbolName("Kotlin_Boolean_toString")
|
public override fun toString() = if (this) "true" else "false"
|
||||||
external public override fun toString(): String
|
|
||||||
|
|
||||||
public override fun hashCode(): Int {
|
public override fun hashCode() = if (this) 1 else 0
|
||||||
return if (this) 1 else 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user