Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Commit

Permalink
Rework memory manager to make stack slot update faster (#2813)
Browse files Browse the repository at this point in the history
  • Loading branch information
olonho committed Apr 9, 2019
1 parent 4dd94d7 commit d072920
Show file tree
Hide file tree
Showing 19 changed files with 875 additions and 511 deletions.
24 changes: 12 additions & 12 deletions Interop/JsRuntime/src/main/kotlin/jsinterop.kt
Expand Up @@ -27,15 +27,15 @@ typealias Pointer = Int
/**
* @Retain annotation is required to preserve functions from internalization and DCE.
*/
@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_allocateArena")
external public fun allocateArena(): Arena

@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_freeArena")
external public fun freeArena(arena: Arena)

@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_pushIntToArena")
external public fun pushIntToArena(arena: Arena, value: Int)

Expand All @@ -49,15 +49,15 @@ fun doubleUpper(value: Double): Int =
fun doubleLower(value: Double): Int =
(value.toBits() and 0x00000000ffffffff) .toInt()

@Retain
@RetainForTarget("wasm")
@SymbolName("ReturnSlot_getDouble")
external public fun ReturnSlot_getDouble(): Double

@Retain
@RetainForTarget("wasm")
@SymbolName("Kotlin_String_utf16pointer")
external public fun stringPointer(message: String): Pointer

@Retain
@RetainForTarget("wasm")
@SymbolName("Kotlin_String_utf16length")
external public fun stringLengthBytes(message: String): Int

Expand All @@ -68,7 +68,7 @@ fun <R> wrapFunction(func: KtFunction<R>): Int {
return ptr.toInt() // TODO: LP64 unsafe.
}

@Retain
@RetainForTarget("wasm")
@ExportForCppRuntime("Konan_js_runLambda")
fun runLambda(pointer: Int, argumentsArena: Arena, argumentsArenaSize: Int): Int {
val arguments = arrayListOf<JsValue>()
Expand Down Expand Up @@ -104,19 +104,19 @@ open class JsArray(arena: Arena, index: Object): JsValue(arena, index) {
get() = this.getInt("length")
}

@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_getInt")
external public fun getInt(arena: Arena, obj: Object, propertyPtr: Pointer, propertyLen: Int): Int;

@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_getProperty")
external public fun Konan_js_getProperty(arena: Arena, obj: Object, propertyPtr: Pointer, propertyLen: Int): Int;

@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_setFunction")
external public fun setFunction(arena: Arena, obj: Object, propertyName: Pointer, propertyLength: Int , function: Int)

@Retain
@RetainForTarget("wasm")
@SymbolName("Konan_js_setString")
external public fun setString(arena: Arena, obj: Object, propertyName: Pointer, propertyLength: Int, stringPtr: Pointer, stringLength: Int )

Expand All @@ -140,4 +140,4 @@ fun JsValue.setter(property: String, string: String) {
object ArenaManager {
val globalArena = allocateArena()
var currentArena = globalArena
}
}
Expand Up @@ -850,31 +850,47 @@ internal class CAdapterGenerator(
|
|extern "C" {
|void UpdateHeapRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|void UpdateStackRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|KObjHeader* AllocInstance(const KTypeInfo*, KObjHeader**) RUNTIME_NOTHROW;
|KObjHeader* DerefStablePointer(void*, KObjHeader**) RUNTIME_NOTHROW;
|void* CreateStablePointer(KObjHeader*) RUNTIME_NOTHROW;
|void DisposeStablePointer(void*) RUNTIME_NOTHROW;
|int IsInstance(const KObjHeader*, const KTypeInfo*) RUNTIME_NOTHROW;
|void EnterFrame(KObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|void LeaveFrame(KObjHeader** start, int parameters, int count) RUNTIME_NOTHROW;
|void Kotlin_initRuntimeIfNeeded();
|
|KObjHeader* CreateStringFromCString(const char*, KObjHeader**);
|char* CreateCStringFromString(const KObjHeader*);
|void DisposeCString(char* cstring);
|} // extern "C"
|
|struct ${prefix}_FrameOverlay {
| void* arena;
| ${prefix}_FrameOverlay* previous;
| ${prefix}_KInt parameters;
| ${prefix}_KInt count;
|};
|
|class KObjHolder {
|public:
| KObjHolder() : obj_(nullptr) {}
| KObjHolder() : obj_(nullptr) {
| EnterFrame(frame(), 0, sizeof(*this)/sizeof(void*));
| }
| explicit KObjHolder(const KObjHeader* obj) : obj_(nullptr) {
| UpdateHeapRef(&obj_, obj);
| EnterFrame(frame(), 0, sizeof(*this)/sizeof(void*));
| UpdateStackRef(&obj_, obj);
| }
| ~KObjHolder() {
| UpdateHeapRef(&obj_, nullptr);
| LeaveFrame(frame(), 0, sizeof(*this)/sizeof(void*));
| }
| KObjHeader* obj() { return obj_; }
| KObjHeader** slot() { return &obj_; }
| private:
| ${prefix}_FrameOverlay frame_;
| KObjHeader* obj_;
|
| KObjHeader** frame() { return reinterpret_cast<KObjHeader**>(&frame_); }
|};
|static void DisposeStablePointerImpl(${prefix}_KNativePtr ptr) {
| DisposeStablePointer(ptr);
Expand Down
Expand Up @@ -996,7 +996,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,

private val kotlinExceptionRtti: ConstPointer
get() = constPointer(importGlobal(
"_ZTI9ObjHolder", // typeinfo for ObjHolder
"_ZTI18ExceptionObjHolder", // typeinfo for ObjHolder
int8TypePtr,
origin = context.stdlibModule.llvmSymbolOrigin
)).bitcast(int8TypePtr)
Expand Down
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.coverage.*
import org.jetbrains.kotlin.backend.konan.llvm.objcexport.is64Bit
import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType
Expand Down Expand Up @@ -681,7 +682,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}


if (declaration.descriptor.retainAnnotation) {
if (declaration.descriptor.retainAnnotation(context.config.target)) {
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
}

Expand Down Expand Up @@ -2190,7 +2191,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)

if (constructor.constructedClass.isExternalObjCClass()) {
if (constructor.constructedClass.isExternalObjCClass() || constructor.constructedClass.isAny()) {
assert(args.isEmpty())
return codegen.theUnitInstanceRef.llvm
}
Expand Down
Expand Up @@ -5,13 +5,18 @@

package org.jetbrains.kotlin.backend.konan.llvm

import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.annotations.*
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.name.FqName

private val annotationName = FqName("kotlin.native.Retain")
private val retainAnnotationName = FqName("kotlin.native.Retain")
private val retainForTargetAnnotationName = FqName("kotlin.native.RetainForTarget")

internal val FunctionDescriptor.retainAnnotation: Boolean
get() {
return (this.annotations.findAnnotation(annotationName) != null)
}

internal fun FunctionDescriptor.retainAnnotation(target: KonanTarget): Boolean {
if (this.annotations.findAnnotation(retainAnnotationName) != null) return true
val forTarget = this.annotations.findAnnotation(retainForTargetAnnotationName)
if (forTarget != null && forTarget.getStringValueOrNull("target") == target.name) return true
return false
}
3 changes: 2 additions & 1 deletion backend.native/tests/build.gradle
Expand Up @@ -2065,7 +2065,7 @@ task extend_exception(type: RunKonanTest) {
}

task check_stacktrace_format(type: RunStandaloneKonanTest) {
disabled = !isAppleTarget(project)
disabled = true // !isAppleTarget(project)
flags = ['-g']
source = "runtime/exceptions/check_stacktrace_format.kt"
}
Expand Down Expand Up @@ -3184,6 +3184,7 @@ task produce_dynamic(type: DynamicKonanTest) {
"enum100 = 100\n" +
"object = 42\n" +
"singleton = I am single\n" +
"mutable = foo\n" +
"topLevel = 777 3\n"
}

Expand Down
2 changes: 2 additions & 0 deletions backend.native/tests/interop/objc/smoke.kt
Expand Up @@ -182,6 +182,8 @@ fun testWeakReference(block: () -> NSObject) {
createAndTestWeakReference(block)
}

kotlin.native.internal.GC.collect()

assertNull(ref.get())
}

Expand Down
4 changes: 4 additions & 0 deletions backend.native/tests/produce_dynamic/simple/hello.kt
Expand Up @@ -14,6 +14,10 @@ fun hello() {

fun getString() = "Kotlin/Native"

data class Data(var string: String)

fun getMutable() = Data("foo")

// Class with inheritance.
open class Base {
open fun foo() = println("Base.foo")
Expand Down
5 changes: 5 additions & 0 deletions backend.native/tests/produce_dynamic/simple/main.c
Expand Up @@ -16,9 +16,11 @@ int main(void) {
T_(I) casted_impl2 = { .pinned = impl2.pinned };
T_(Enum) enum1 = __ kotlin.root.Enum.HUNDRED.get();
T_(Codeable) object1 = __ kotlin.root.get_an_object();
T_(Data) data = __ kotlin.root.getMutable();

const char* string1 = __ kotlin.root.getString();
const char* string2 = __ kotlin.root.Singleton.toString(singleton);
const char* string3 = __ kotlin.root.Data.get_string(data);

__ kotlin.root.hello();
__ kotlin.root.Base.foo(base);
Expand All @@ -40,6 +42,8 @@ int main(void) {

printf("singleton = %s\n", string2);

printf("mutable = %s\n", string3);

topLevelFunctionVoidFromC(42, 0);
__ kotlin.root.topLevelFunctionVoid(42, 0);
printf("topLevel = %d %d\n", topLevelFunctionFromC(780, 3), __ kotlin.root.topLevelFunctionFromCShort(5, 2));
Expand All @@ -49,6 +53,7 @@ int main(void) {
__ DisposeStablePointer(singleton.pinned);
__ DisposeString(string1);
__ DisposeString(string2);
__ DisposeString(string3);
__ DisposeStablePointer(base.pinned);
__ DisposeStablePointer(child.pinned);
__ DisposeStablePointer(impl1.pinned);
Expand Down
5 changes: 4 additions & 1 deletion backend.native/tests/runtime/memory/weak0.kt
Expand Up @@ -13,7 +13,6 @@ data class Data(val s: String)
fun localWeak(): WeakReference<Data> {
val x = Data("Hello")
val weak = WeakReference(x)

println(weak.get())
return weak
}
Expand All @@ -29,10 +28,14 @@ fun multiWeak(): Array<WeakReference<Data>> {

@Test fun runTest() {
val weak = localWeak()
kotlin.native.internal.GC.collect()
val value = weak.get()
println(value?.toString())

val weaks = multiWeak()

kotlin.native.internal.GC.collect()

weaks.forEach {
it -> if (it.get()?.s != null) throw Error("not null")
}
Expand Down
5 changes: 3 additions & 2 deletions runtime/src/launcher/cpp/launcher.cpp
Expand Up @@ -29,8 +29,9 @@ OBJ_GETTER(setupArgs, int argc, const char** argv) {
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, argc - 1, OBJ_RESULT);
ArrayHeader* array = result->array();
for (int index = 1; index < argc; index++) {
CreateStringFromCString(
argv[index], ArrayAddressOfElementAt(array, index - 1));
ObjHolder result;
CreateStringFromCString(argv[index], result.slot());
UpdateHeapRef(ArrayAddressOfElementAt(array, index - 1), result.obj());
}
return result;
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/main/cpp/Atomic.cpp
Expand Up @@ -208,7 +208,7 @@ OBJ_GETTER(Kotlin_AtomicReference_get, KRef thiz) {
// 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(ReadRefLocked, &ref->value_, &ref->lock_);
RETURN_RESULT_OF(ReadHeapRefLocked, &ref->value_, &ref->lock_);
}

} // extern "C"
1 change: 1 addition & 0 deletions runtime/src/main/cpp/Common.h
Expand Up @@ -24,6 +24,7 @@
#define RUNTIME_USED __attribute__((used))

#define ALWAYS_INLINE __attribute__((always_inline))
#define NO_INLINE __attribute__((noinline))

#if KONAN_NO_THREADS
#define THREAD_LOCAL_VARIABLE
Expand Down
16 changes: 11 additions & 5 deletions runtime/src/main/cpp/Exceptions.cpp
Expand Up @@ -156,7 +156,9 @@ OBJ_GETTER0(GetCurrentStackTrace) {
OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
#if OMIT_BACKTRACE
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT);
CreateStringFromCString("<UNIMPLEMENTED>", ArrayAddressOfElementAt(result->array(), 0));
ObjHolder holder;
CreateStringFromCString("<UNIMPLEMENTED>", holder.slot());
UpdateHeapRef(ArrayAddressOfElementAt(result->array(), 0), holder.obj());
return result;
#else
uint32_t size = stackTrace->array()->count_;
Expand All @@ -172,7 +174,9 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
}
char line[512];
konan::snprintf(line, sizeof(line) - 1, "%s (%p)", symbol, (void*)(intptr_t)address);
CreateStringFromCString(line, ArrayAddressOfElementAt(strings->array(), index));
ObjHolder holder;
CreateStringFromCString(line, holder.slot());
UpdateHeapRef(ArrayAddressOfElementAt(strings->array(), index), holder.obj());
}
#else
if (size > 0) {
Expand All @@ -195,7 +199,9 @@ OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
} else {
result = symbol;
}
CreateStringFromCString(result, ArrayAddressOfElementAt(strings->array(), index));
ObjHolder holder;
CreateStringFromCString(result, holder.slot());
UpdateHeapRef(ArrayAddressOfElementAt(strings->array(), index), holder.obj());
}
}
#endif
Expand All @@ -210,7 +216,7 @@ void ThrowException(KRef exception) {
PrintThrowable(exception);
RuntimeCheck(false, "Exceptions unsupported");
#else
throw ObjHolder(exception);
throw ExceptionObjHolder(exception);
#endif
}

Expand Down Expand Up @@ -276,7 +282,7 @@ static void KonanTerminateHandler() {
} else {
try {
std::rethrow_exception(currentException);
} catch (ObjHolder& e) {
} catch (ExceptionObjHolder& e) {
TerminateWithUnhandledException(e.obj());
} catch (...) {
// Not a Kotlin exception.
Expand Down
13 changes: 6 additions & 7 deletions runtime/src/main/cpp/KString.cpp
Expand Up @@ -1176,23 +1176,22 @@ OBJ_GETTER(Kotlin_String_subSequence, KString thiz, KInt startIndex, KInt endInd
RETURN_RESULT_OF0(TheEmptyString);
}
KInt length = endIndex - startIndex;
ArrayHeader* result = AllocArrayInstance(
theStringTypeInfo, length, OBJ_RESULT)->array();
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, length, OBJ_RESULT)->array();
memcpy(CharArrayAddressOfElementAt(result, 0),
CharArrayAddressOfElementAt(thiz, startIndex),
length * sizeof(KChar));
RETURN_OBJ(result->obj());
}

const KChar* Kotlin_String_utf16pointer(KString message) {
RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string");
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
return utf16;
RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string");
const KChar* utf16 = CharArrayAddressOfElementAt(message, 0);
return utf16;
}

KInt Kotlin_String_utf16length(KString message) {
RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string");
return message->count_ * sizeof(KChar);
RuntimeAssert(message->type_info() == theStringTypeInfo, "Must use a string");
return message->count_ * sizeof(KChar);
}


Expand Down

0 comments on commit d072920

Please sign in to comment.