Make String and box types frozen by default, more freeze checks (#1645)

This commit is contained in:
Nikolay Igotti
2018-06-06 11:59:16 +03:00
committed by GitHub
parent 45052ded8e
commit afc7d1dd9e
19 changed files with 226 additions and 32 deletions
@@ -18,13 +18,9 @@ package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.typeUtil.isUnit
@@ -87,11 +83,18 @@ internal fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction {
}
private val intrinsicAnnotation = FqName("konan.internal.Intrinsic")
private val immutableAnnotation = FqName("konan.internal.Immutable")
// TODO: don't forget to remove descriptor access here.
internal val FunctionDescriptor.isIntrinsic: Boolean
get() = this.descriptor.annotations.hasAnnotation(intrinsicAnnotation)
internal val org.jetbrains.kotlin.descriptors.DeclarationDescriptor.isImmutable: Boolean
get() = this.annotations.hasAnnotation(immutableAnnotation)
internal val DeclarationDescriptor.isImmutable: Boolean
get() = this.descriptor.isImmutable
private val intrinsicTypes = setOf(
"kotlin.Boolean", "kotlin.Char",
"kotlin.Byte", "kotlin.Short",
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
@@ -1397,8 +1398,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val thisPtr = evaluateExpression(value.receiver!!)
return functionGenerationContext.loadSlot(
fieldPtrOfClass(thisPtr, value.symbol.owner), value.descriptor.isVar())
}
else {
} else {
assert (value.receiver == null)
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
return functionGenerationContext.loadSlot(ptr, value.descriptor.isVar())
@@ -1406,18 +1406,25 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
//-------------------------------------------------------------------------//
// TODO: rewrite in IR!
private fun needMutationCheck(descriptor: org.jetbrains.kotlin.descriptors.DeclarationDescriptor): Boolean {
// For now we omit mutation checks on immutable types, as this allows initialization in constructor
// and it is assumed that API doesn't allow to change them.
return !descriptor.isImmutable
}
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
context.log{"evaluateSetField : ${ir2string(value)}"}
val valueToAssign = evaluateExpression(value.value)
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = evaluateExpression(value.receiver!!)
functionGenerationContext.call(context.llvm.mutationCheck,
listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)),
Lifetime.IRRELEVANT, ExceptionHandler.Caller)
if (needMutationCheck(value.descriptor.containingDeclaration)) {
functionGenerationContext.call(context.llvm.mutationCheck,
listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)),
Lifetime.IRRELEVANT, ExceptionHandler.Caller)
}
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner))
}
else {
} else {
assert (value.receiver == null)
val globalValue = context.llvmDeclarations.forStaticField(value.symbol.owner).storage
functionGenerationContext.storeAny(valueToAssign, globalValue)
@@ -29,6 +29,13 @@ import org.jetbrains.kotlin.resolve.constants.StringValue
internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun flagsFromClass(classDescriptor: ClassDescriptor): Int {
var result = 0
if (classDescriptor.isImmutable)
result = result or 1 /* TF_IMMUTABLE */
return result
}
private inner class FieldTableRecord(val nameSignature: LocalHash, val fieldOffset: Int) :
Struct(runtime.fieldTableRecordType, nameSignature, Int32(fieldOffset))
@@ -50,6 +57,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
fieldsCount: Int,
packageName: String?,
relativeName: String?,
flags: Int,
extendedInfo: ConstPointer,
writableTypeInfo: ConstPointer?) :
@@ -78,6 +86,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
kotlinStringLiteral(packageName),
kotlinStringLiteral(relativeName),
Int32(flags),
extendedInfo,
*listOfNotNull(writableTypeInfo).toTypedArray()
@@ -203,6 +213,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
fieldsPtr, if (classDesc.isInterface) -1 else fields.size,
reflectionInfo.packageName,
reflectionInfo.relativeName,
flagsFromClass(classDesc),
makeExtendedInfo(classDesc),
llvmDeclarations.writableTypeInfoGlobal?.pointer
)
@@ -345,6 +356,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
fields = fieldsPtr, fieldsCount = fieldsCount,
packageName = reflectionInfo.packageName,
relativeName = reflectionInfo.relativeName,
flags = flagsFromClass(descriptor),
extendedInfo = NullPointer(runtime.extendedTypeInfoType),
writableTypeInfo = writableTypeInfo
), vtable)
@@ -199,7 +199,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
element.acceptChildrenVoid(this)
}
fun IrFunctionSymbol.hasAnnotatoin(fqName: FqName) = descriptor.annotations.any { it.fqName == fqName }
fun IrFunctionSymbol.hasAnnotation(fqName: FqName) = descriptor.annotations.any { it.fqName == fqName }
fun registerClassFunction(classDescriptor: ClassDescriptor,
function: IrFunctionSymbol,
@@ -263,7 +263,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
val symbol = declaration.symbol
val owner = declaration.descriptor.containingDeclaration
val kinds = FunctionKind.values().filter { symbol.hasAnnotatoin(it.annotationFqName) }
val kinds = FunctionKind.values().filter { symbol.hasAnnotation(it.annotationFqName) }
if (kinds.isEmpty()) {
return
}
+8
View File
@@ -663,6 +663,14 @@ task freeze_stress(type: RunKonanTest) {
source = "runtime/workers/freeze_stress.kt"
}
task freeze2(type: RunKonanTest) {
disabled = (project.testTarget == 'wasm32') // No exceptions on WASM.
goldValue =
"Worker 1: Hello world\n" + "Worker2: 42\n" +
"Worker3: 239.0\n" + "Worker4: a\n" + "OK\n"
source = "runtime/workers/freeze2.kt"
}
task enumIdentity(type: RunKonanTest) {
disabled = (project.testTarget == 'wasm32') // Workers need pthreads.
goldValue = "true\n"
@@ -38,6 +38,6 @@ data class SharedData(val string: String, val int: Int, val member: SharedDataMe
future.consume {
result -> println("Main: $result")
}
worker.requestTermination().consume { _ -> }
worker.requestTermination().result()
println("OK")
}
@@ -0,0 +1,101 @@
/*
* 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.
*/
package runtime.workers.freeze2
import kotlin.test.*
import konan.worker.*
data class Data(var int: Int)
@Test fun runTest() {
// Ensure that we can not mutate frozen objects and arrays.
val a0 = Data(2)
a0.int++
a0.freeze()
assertFailsWith<InvalidMutabilityException> {a0.int++ }
val a1 = ByteArray(2)
a1[1]++
a1.freeze()
assertFailsWith<InvalidMutabilityException> { a1[1]++ }
val a2 = ShortArray(2)
a2[1]++
a2.freeze()
assertFailsWith<InvalidMutabilityException> { a2[1]++ }
val a3 = IntArray(2)
a3[1]++
a3.freeze()
assertFailsWith<InvalidMutabilityException> { a3[1]++ }
val a4 = LongArray(2)
a4[1]++
a4.freeze()
assertFailsWith<InvalidMutabilityException> { a4[1]++ }
val a5 = BooleanArray(2)
a5[1] = true
a5.freeze()
assertFailsWith<InvalidMutabilityException> { a5[1] = false }
val a6 = CharArray(2)
a6[1] = 'a'
a6.freeze()
assertFailsWith<InvalidMutabilityException> { a6[1] = 'b' }
val a7 = FloatArray(2)
a7[1] = 1.0f
a7.freeze()
assertFailsWith<InvalidMutabilityException> { a7[1] = 2.0f }
val a8 = DoubleArray(2)
a8[1] = 1.0
a8.freeze()
assertFailsWith<InvalidMutabilityException> { a8[1] = 2.0 }
// Ensure that String and integral boxes are frozen by default, by passing local to the worker.
val worker = startWorker()
var data: Any = "Hello" + " " + "world"
assert(data.isFrozen)
worker.schedule(TransferMode.CHECKED, { data } ) {
input -> println("Worker 1: $input")
}.result()
data = 42
assert(data.isFrozen)
worker.schedule(TransferMode.CHECKED, { data } ) {
input -> println("Worker2: $input")
}.result()
data = 239.0
assert(data.isFrozen)
worker.schedule(TransferMode.CHECKED, { data } ) {
input -> println("Worker3: $input")
}.result()
data = 'a'
assert(data.isFrozen)
worker.schedule(TransferMode.CHECKED, { data } ) {
input -> println("Worker4: $input")
}.result()
worker.requestTermination().result()
println("OK")
}
@@ -4,7 +4,8 @@ import kotlin.test.*
import konan.worker.*
data class WorkerArgument(val intParam: Int, val stringParam: String)
data class DataParam(var int: Int)
data class WorkerArgument(val intParam: Int, val dataParam: DataParam)
data class WorkerResult(val intResult: Int, val stringResult: String)
@Test fun runTest() {
@@ -13,19 +14,18 @@ data class WorkerResult(val intResult: Int, val stringResult: String)
fun main(args: Array<String>) {
val worker = startWorker()
val s = "zzz${args.size.toString()}"
val dataParam = DataParam(17)
val future = try {
worker.schedule(TransferMode.CHECKED,
{ WorkerArgument(42, s) },
{ input -> WorkerResult(input.intParam, input.stringParam + " result") }
{ WorkerArgument(42, dataParam) },
{ input -> WorkerResult(input.intParam, input.dataParam.toString() + " result") }
)
} catch (e: IllegalStateException) {
null
}
if (future != null)
println("Fail 1")
if (s != "zzz0") println("Fail 2")
if (dataParam.int != 17) println("Fail 2")
worker.requestTermination().consume { _ -> }
println("OK")
}
+37 -9
View File
@@ -23,9 +23,22 @@
#include "Natives.h"
#include "Types.h"
namespace {
const ArrayHeader anEmptyArray = {
const_cast<TypeInfo*>(theArrayTypeInfo), /* permanent object */ 0, /* element count */ 0
};
ALWAYS_INLINE inline void mutabilityCheck(KConstRef thiz) {
// TODO: optimize it!
if (thiz->container()->frozen()) {
ThrowInvalidMutabilityException();
}
}
template<typename T>
static inline void copyImpl(KConstRef thiz, KInt fromIndex,
KRef destination, KInt toIndex, KInt count) {
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 ||
@@ -33,18 +46,12 @@ static inline void copyImpl(KConstRef thiz, KInt fromIndex,
toIndex < 0 || count > destinationArray->count_ - toIndex) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(destination);
memmove(PrimitiveArrayAddressOfElementAt<T>(destinationArray, toIndex),
PrimitiveArrayAddressOfElementAt<T>(array, fromIndex),
count * sizeof(T));
}
namespace {
const ArrayHeader anEmptyArray = {
const_cast<TypeInfo*>(theArrayTypeInfo), /* permanent object */ 0, /* element count */ 0
};
} // namespace
extern "C" {
@@ -65,6 +72,7 @@ void Kotlin_Array_set(KRef thiz, KInt index, KConstRef value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
UpdateRef(ArrayAddressOfElementAt(array, index), value);
}
@@ -78,6 +86,7 @@ void Kotlin_Array_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KRef value)
if (fromIndex < 0 || toIndex < fromIndex || toIndex > array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
for (KInt index = fromIndex; index < toIndex; ++index) {
UpdateRef(ArrayAddressOfElementAt(array, index), value);
}
@@ -92,6 +101,7 @@ void Kotlin_Array_copyImpl(KConstRef thiz, KInt fromIndex,
toIndex < 0 || count > destinationArray->count_ - toIndex) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(destination);
if (fromIndex >= toIndex) {
for (int index = 0; index < count; index++) {
UpdateRef(ArrayAddressOfElementAt(destinationArray, toIndex + index),
@@ -123,6 +133,7 @@ void Kotlin_ByteArray_set(KRef thiz, KInt index, KByte value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*ByteArrayAddressOfElementAt(array, index) = value;
}
@@ -184,6 +195,7 @@ void Kotlin_ByteArray_setCharAt(KRef thiz, KInt index, KChar value) {
if (static_cast<uint32_t>(index + 1) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*reinterpret_cast<KChar*>(ByteArrayAddressOfElementAt(array, index)) = value;
}
@@ -192,6 +204,7 @@ void Kotlin_ByteArray_setShortAt(KRef thiz, KInt index, KShort value) {
if (static_cast<uint32_t>(index + 1) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*reinterpret_cast<KShort*>(ByteArrayAddressOfElementAt(array, index)) = value;
}
@@ -200,6 +213,7 @@ void Kotlin_ByteArray_setIntAt(KRef thiz, KInt index, KInt value) {
if (static_cast<uint32_t>(index + 3) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*reinterpret_cast<KInt*>(ByteArrayAddressOfElementAt(array, index)) = value;
}
@@ -208,6 +222,7 @@ void Kotlin_ByteArray_setLongAt(KRef thiz, KInt index, KLong value) {
if (static_cast<uint32_t>(index + 7) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*reinterpret_cast<KLong*>(ByteArrayAddressOfElementAt(array, index)) = value;
}
@@ -216,6 +231,7 @@ void Kotlin_ByteArray_setFloatAt(KRef thiz, KInt index, KFloat value) {
if (static_cast<uint32_t>(index + 3) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*reinterpret_cast<KFloat*>(ByteArrayAddressOfElementAt(array, index)) = value;
}
@@ -224,6 +240,7 @@ void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) {
if (static_cast<uint32_t>(index + 7) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*reinterpret_cast<KDouble*>(ByteArrayAddressOfElementAt(array, index)) = value;
}
@@ -240,11 +257,15 @@ void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KChar>(array, 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_ < newSize ? array->count_ : newSize;
@@ -273,6 +294,7 @@ void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KShort>(array, index) = value;
}
@@ -294,6 +316,7 @@ void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KInt>(array, index) = value;
}
@@ -307,6 +330,7 @@ void Kotlin_IntArray_fillImpl(KRef thiz, KInt fromIndex, KInt toIndex, KInt valu
if (fromIndex < 0 || toIndex < fromIndex || toIndex >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
for (KInt index = fromIndex; index < toIndex; ++index) {
*PrimitiveArrayAddressOfElementAt<KInt>(array, index) = value;
}
@@ -366,6 +390,7 @@ void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KLong>(array, index) = value;
}
@@ -387,6 +412,7 @@ void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KFloat>(array, index) = value;
}
@@ -408,6 +434,7 @@ void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KDouble>(array, index) = value;
}
@@ -429,6 +456,7 @@ void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) {
if (static_cast<uint32_t>(index) >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
mutabilityCheck(thiz);
*PrimitiveArrayAddressOfElementAt<KBoolean>(array, index) = value;
}
+2
View File
@@ -50,6 +50,8 @@ void RUNTIME_NORETURN ThrowOutOfMemoryError();
void RUNTIME_NORETURN ThrowNotImplementedError();
// Throws illegal character conversion exception (used in UTF8/UTF16 conversions).
void RUNTIME_NORETURN ThrowIllegalCharacterConversionException();
void RUNTIME_NORETURN ThrowIllegalArgumentException();
void RUNTIME_NORETURN ThrowInvalidMutabilityException();
// Prints out mesage of Throwable.
void PrintThrowable(KRef);
+4
View File
@@ -264,6 +264,9 @@ class Container {
void SetHeader(ObjHeader* obj, const TypeInfo* type_info) {
obj->container_ = header_;
obj->typeInfoOrMeta_ = const_cast<TypeInfo*>(type_info);
// Take into account typeInfo's immutability for ARC strategy.
if ((type_info->flags_ & TF_IMMUTABLE) != 0)
header_->refCount_ |= CONTAINER_TAG_FROZEN;
}
};
@@ -341,6 +344,7 @@ class ArenaContainer {
void setHeader(ObjHeader* obj, const TypeInfo* typeInfo) {
obj->container_ = currentChunk_->asHeader();
obj->typeInfoOrMeta_ = const_cast<TypeInfo*>(typeInfo);
// Here we do not take into account typeInfo's immutability for ARC strategy, as there's no ARC.
}
ContainerChunk* currentChunk_;
+7
View File
@@ -57,6 +57,10 @@ enum Konan_RuntimeType {
RT_BOOLEAN = 9
};
enum Konan_TypeFlags {
TF_IMMUTABLE = 1 << 0
};
// Extended information about a type.
struct ExtendedTypeInfo {
// Number of fields (negated Konan_RuntimeType for array types).
@@ -104,6 +108,9 @@ struct TypeInfo {
// or `null` if the class is anonymous.
ObjHeader* relativeName_;
// Various flags.
int32_t flags_;
// Extended RTTI.
const ExtendedTypeInfo* extendedInfo_;
+1 -1
View File
@@ -577,7 +577,7 @@ void Kotlin_Worker_freezeInternal(KRef object) {
}
KBoolean Kotlin_Worker_isFrozenInternal(KRef object) {
return object == nullptr || object->container()->frozen();
return object == nullptr || object->container()->permanentOrFrozen();
}
} // extern "C"
@@ -22,6 +22,7 @@ import kotlinx.cinterop.*
* An immutable compile-time array of bytes.
*/
@ExportTypeInfo("theImmutableBinaryBlobTypeInfo")
@Immutable
public final class ImmutableBinaryBlob private constructor() {
public val size: Int
get() = getArrayLength()
@@ -58,3 +58,9 @@ annotation class ExportForCompiler
@Retention(AnnotationRetention.BINARY)
annotation class InlineConstructor
/**
* Class is immutable and is frozen by default.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class Immutable
@@ -16,7 +16,6 @@
package konan.internal
@SymbolName("getCachedBooleanBox")
external fun getCachedBooleanBox(value: Boolean): BooleanBox
@SymbolName("inBooleanBoxCache")
@@ -42,6 +41,7 @@ external fun getCachedLongBox(value: Long): LongBox
@SymbolName("inLongBoxCache")
external fun inLongBoxCache(value: Long): Boolean
@Immutable
class BooleanBox(val value: Boolean) : Comparable<Boolean> {
override fun equals(other: Any?): Boolean {
if (other !is BooleanBox) {
@@ -65,6 +65,7 @@ fun boxBoolean(value: Boolean) = if (inBooleanBoxCache(value)) {
BooleanBox(value)
}
@Immutable
class CharBox(val value: Char) : Comparable<Char> {
override fun equals(other: Any?): Boolean {
if (other !is CharBox) {
@@ -88,6 +89,7 @@ fun boxChar(value: Char) = if (inCharBoxCache(value)) {
CharBox(value)
}
@Immutable
class ByteBox(val value: Byte) : Number(), Comparable<Byte> {
override fun equals(other: Any?): Boolean {
if (other !is ByteBox) {
@@ -119,6 +121,7 @@ fun boxByte(value: Byte) = if (inByteBoxCache(value)) {
ByteBox(value)
}
@Immutable
class ShortBox(val value: Short) : Number(), Comparable<Short> {
override fun equals(other: Any?): Boolean {
if (other !is ShortBox) {
@@ -150,6 +153,7 @@ fun boxShort(value: Short) = if (inShortBoxCache(value)) {
ShortBox(value)
}
@Immutable
class IntBox(val value: Int) : Number(), Comparable<Int> {
override fun equals(other: Any?): Boolean {
if (other !is IntBox) {
@@ -181,6 +185,7 @@ fun boxInt(value: Int) = if (inIntBoxCache(value)) {
IntBox(value)
}
@Immutable
class LongBox(val value: Long) : Number(), Comparable<Long> {
override fun equals(other: Any?): Boolean {
if (other !is LongBox) {
@@ -212,6 +217,7 @@ fun boxLong(value: Long) = if (inLongBoxCache(value)) {
LongBox(value)
}
@Immutable
class FloatBox(val value: Float) : Number(), Comparable<Float> {
override fun equals(other: Any?): Boolean {
if (other !is FloatBox) {
@@ -239,6 +245,7 @@ class FloatBox(val value: Float) : Number(), Comparable<Float> {
@ExportForCppRuntime("Kotlin_boxFloat")
fun boxFloat(value: Float) = FloatBox(value)
@Immutable
class DoubleBox(val value: Double) : Number(), Comparable<Double> {
override fun equals(other: Any?): Boolean {
if (other !is DoubleBox) {
@@ -18,6 +18,7 @@ package konan.internal
import kotlinx.cinterop.*
@Immutable
class NativePtrBox(val value: NativePtr) {
override fun equals(other: Any?): Boolean {
if (other !is NativePtrBox) {
@@ -34,6 +35,7 @@ class NativePtrBox(val value: NativePtr) {
fun boxNativePtr(value: NativePtr) = NativePtrBox(value)
@Immutable
class NativePointedBox(val value: NativePointed) {
override fun equals(other: Any?): Boolean {
if (other !is NativePointedBox) {
@@ -54,6 +56,7 @@ class NativePointedBox(val value: NativePointed) {
fun boxNativePointed(value: NativePointed?) = if (value != null) NativePointedBox(value) else null
fun unboxNativePointed(box: NativePointedBox?) = box?.value
@Immutable
class CPointerBox(val value: CPointer<CPointed>) : CValuesRef<CPointed>() {
override fun equals(other: Any?): Boolean {
if (other !is CPointerBox) {
@@ -65,6 +65,11 @@ fun ThrowUninitializedPropertyAccessException(): Nothing {
throw UninitializedPropertyAccessException()
}
@ExportForCppRuntime
internal fun ThrowIllegalArgumentException() : Nothing {
throw IllegalArgumentException()
}
@ExportForCppRuntime
internal fun ThrowNotImplementedError(): Nothing {
throw NotImplementedError("An operation is not implemented.")
+1 -1
View File
@@ -16,8 +16,8 @@
package kotlin
@ExportTypeInfo("theStringTypeInfo")
@konan.internal.Immutable
public final class String : Comparable<String>, CharSequence {
public companion object {
}