Skip to content

Commit

Permalink
Rewind() called early in TransferContext (#512)
Browse files Browse the repository at this point in the history
* Rewind is called early whenever the buffer has to be used.
  • Loading branch information
CedNaru authored Oct 14, 2023
1 parent 46a5058 commit 41857e8
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 65 deletions.
9 changes: 1 addition & 8 deletions kt/godot-library/src/main/kotlin/godot/core/Constructors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,7 @@ abstract class KtConstructor<T : KtObject>(
abstract operator fun invoke(): T

fun construct(rawPtr: VoidPtr, instanceId: Long) = KtObject.instantiateWith(rawPtr, instanceId) {
val argsSize = TransferContext.buffer.int
require(argsSize == parameterCount) {
"Expecting $parameterCount parameter(s) for constructor, but got $argsSize instead."
}
for (i in 0 until parameterCount) {
paramsArray[i] = TransferContext.readSingleArgument(parameterTypes[i], parameterNullables[i])
}
TransferContext.buffer.rewind()
TransferContext.readArguments(parameterTypes, parameterNullables, paramsArray)
val instance = invoke()
resetParamsArray()
instance
Expand Down
11 changes: 2 additions & 9 deletions kt/godot-library/src/main/kotlin/godot/core/KtObject.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,12 @@ abstract class KtObject {

internal inline fun callConstructor(classIndex: Int, scriptIndex: Int): Unit {
TransferContext.createNativeObject(classIndex, this, scriptIndex)
readPtrAndIdFromBuffer()
TransferContext.initializeKtObject(this)
}

internal inline fun getSingleton(classIndex: Int) {
TransferContext.getSingleton(classIndex)
readPtrAndIdFromBuffer()
}

private inline fun readPtrAndIdFromBuffer() {
val buffer = TransferContext.buffer
rawPtr = buffer.long
id = ObjectID(buffer.long)
buffer.rewind()
TransferContext.initializeKtObject(this)
}

open fun _onDestroy() = Unit
Expand Down
3 changes: 0 additions & 3 deletions kt/godot-library/src/main/kotlin/godot/core/Properties.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,8 @@ open class KtProperty<T : KtObject, P : Any?>(
}

protected fun <P> extractSetterArgument(): P {
val argsSize = TransferContext.buffer.int
require(argsSize == 1) { "Setter should be called with only one argument." }
//TODO: manage nullable argument of enum setter (only for objects)
val arg = TransferContext.readSingleArgument(variantType)
TransferContext.buffer.rewind()
@Suppress("UNCHECKED_CAST")
return arg as P
}
Expand Down
15 changes: 3 additions & 12 deletions kt/godot-library/src/main/kotlin/godot/core/callable/KtCallable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,17 @@ abstract class KtCallable<T : KtObject, R : Any?>(
val variantType: VariantType,
vararg parameterTypes: Pair<VariantType, Boolean>
) {
private val types: List<VariantType> = parameterTypes.map { it.first }
private val isNullables: List<Boolean> = parameterTypes.map { it.second }
private val types: Array<VariantType> = parameterTypes.map { it.first }.toTypedArray()
private val isNullables: Array<Boolean> = parameterTypes.map { it.second }.toTypedArray()

fun invoke(instance: T) {
val argsSize = TransferContext.buffer.int
require(argsSize == parameterCount) { "Expecting $parameterCount parameter(s) for function $name, but got $argsSize instead." }
readArguments(argsSize)
TransferContext.readArguments(types, isNullables, paramsArray)
val ret = invokeKt(instance)
resetParamsArray()

TransferContext.writeReturnValue(ret, variantType)
}

private fun readArguments(argsSize: Int) {
for (i in 0 until argsSize) {
paramsArray[i] = TransferContext.readSingleArgument(types[i], isNullables[i])
}
TransferContext.buffer.rewind()
}

companion object {
val paramsArray by threadLocal {
Array<Any?>(Constraints.MAX_FUNCTION_ARG_COUNT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package godot.core.memory

import godot.core.KtObject
import godot.core.LongStringQueue
import godot.core.ObjectID
import godot.core.VariantType
import godot.tools.common.constants.Constraints
import godot.util.VoidPtr
Expand All @@ -22,32 +23,51 @@ internal object TransferContext {
return (LongStringQueue.stringMaxSize + 12).coerceAtLeast(68) * Constraints.MAX_FUNCTION_ARG_COUNT + 4
}

val buffer by threadLocalLazy<ByteBuffer> {
private val buffer by threadLocalLazy<ByteBuffer> {
val buf = ByteBuffer.allocateDirect(bufferSize)
buf.order(ByteOrder.LITTLE_ENDIAN)
buf
}

fun writeArguments(vararg values: Pair<VariantType, Any?>) {
buffer.rewind()
buffer.putInt(values.size)
for (value in values) {
value.first.toGodot(buffer, value.second)
}
}

fun readSingleArgument(variantType: VariantType, isNullable: Boolean = false): Any? {
buffer.rewind()
val argsSize = buffer.int
require(argsSize == 1) {
"Expecting 1 parameter, but got $argsSize instead."
}
return variantType.toKotlin(buffer, isNullable)
}

fun readSingleArgument(variantType: VariantType, isNullable: Boolean = false) =
variantType.toKotlin(buffer, isNullable)
fun readArguments(variantTypes: Array<VariantType>, areNullable: Array<Boolean>, returnArray: Array<Any?>) {
buffer.rewind()
val argsSize = buffer.int
val argumentCount = variantTypes.size
require(argsSize == argumentCount) {
"Expecting $argumentCount parameter(s), but got $argsSize instead."
}

// Assume that variantTypes and areNullable have the same size and that returnArray is big enough
for (i in 0 until argsSize) {
returnArray[i] = variantTypes[i].toKotlin(buffer, areNullable[i])
}
}

fun writeReturnValue(value: Any?, type: VariantType) {
type.toGodot(buffer, value)
buffer.rewind()
type.toGodot(buffer, value)
}

fun readReturnValue(type: VariantType, isNullable: Boolean = false): Any? {
val ret = type.toKotlin(buffer, isNullable)
buffer.rewind()
return ret
return type.toKotlin(buffer, isNullable)
}

fun callMethod(ptr: VoidPtr, methodIndex: Int, expectedReturnType: VariantType) {
Expand All @@ -58,6 +78,12 @@ internal object TransferContext {
)
}

fun initializeKtObject(obj: KtObject) {
buffer.rewind()
obj.rawPtr = buffer.long
obj.id = ObjectID(buffer.long)
}

fun removeScriptInstance(id: Long) {
MemoryManager.unregisterScriptInstance(id)
}
Expand Down
37 changes: 18 additions & 19 deletions src/memory/transfer_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ TransferContext::~TransferContext() {
}
}

SharedBuffer* TransferContext::get_buffer(jni::Env& p_env) {
SharedBuffer* TransferContext::get_and_rewind_buffer(jni::Env& p_env) {
thread_local static SharedBuffer shared_buffer;

if (unlikely(!shared_buffer.is_init())) {
Expand All @@ -43,7 +43,7 @@ SharedBuffer* TransferContext::get_buffer(jni::Env& p_env) {
shared_buffer = SharedBuffer {address, 0};
#endif
}

shared_buffer.rewind();
return &shared_buffer;
}

Expand All @@ -55,30 +55,31 @@ void TransferContext::remove_script_instance(uint64_t id) {
}

void TransferContext::read_return_value(jni::Env& p_env, Variant& r_ret) {
SharedBuffer* buffer {get_buffer(p_env)};
SharedBuffer* buffer {get_and_rewind_buffer(p_env)};
ktvariant::get_variant_from_buffer(buffer, r_ret);
buffer->rewind();
}

void TransferContext::write_args(jni::Env& p_env, const Variant** p_args, int args_size) {
SharedBuffer* buffer {get_buffer(p_env)};
SharedBuffer* buffer {get_and_rewind_buffer(p_env)};
buffer->increment_position(encode_uint32(args_size, buffer->get_cursor()));
for (auto i = 0; i < args_size; ++i) {
ktvariant::send_variant_to_buffer(*p_args[i], buffer);
}
buffer->rewind();
}

uint32_t TransferContext::read_args(jni::Env& p_env, Variant* args) {
SharedBuffer* buffer {get_buffer(p_env)};
SharedBuffer* buffer {get_and_rewind_buffer(p_env)};
uint32_t size {read_args_size(buffer)};
for (uint32_t i = 0; i < size; ++i) {
ktvariant::get_variant_from_buffer(buffer, args[i]);
}
buffer->rewind();
return size;
}

void TransferContext::write_return_value(jni::Env& p_env, Variant& variant) {
ktvariant::send_variant_to_buffer(variant, get_and_rewind_buffer(p_env));
}

void TransferContext::icall(JNIEnv* rawEnv, jobject instance, jlong j_ptr, jint p_method_index, jint expectedReturnType) {
if (unlikely(stack_offset == -1)) {
for (int i = 0; i < MAX_STACK_SIZE; i++) {
Expand All @@ -90,7 +91,7 @@ void TransferContext::icall(JNIEnv* rawEnv, jobject instance, jlong j_ptr, jint
TransferContext* transfer_context {GDKotlin::get_instance().transfer_context};
jni::Env env {rawEnv};

SharedBuffer* buffer {transfer_context->get_buffer(env)};
SharedBuffer* buffer {transfer_context->get_and_rewind_buffer(env)};
uint32_t args_size {read_args_size(buffer)};

auto* ptr {reinterpret_cast<Object*>(static_cast<uintptr_t>(j_ptr))};
Expand Down Expand Up @@ -118,18 +119,22 @@ void TransferContext::icall(JNIEnv* rawEnv, jobject instance, jlong j_ptr, jint
}

const Variant& ret_value {methodBind->call(ptr, args_ptr, args_size, r_error)};
write_return_value(buffer, ret_value);

buffer->rewind();
ktvariant::send_variant_to_buffer(ret_value, buffer);
} else {
Variant* args {variant_args + stack_offset};
read_args_to_array(buffer, args, args_size);


const Variant** args_ptr {variant_args_ptr + stack_offset};

stack_offset += args_size;
const Variant& ret_value {methodBind->call(ptr, args_ptr, args_size, r_error)};
stack_offset -= args_size;

write_return_value(buffer, ret_value);
buffer->rewind();
ktvariant::send_variant_to_buffer(ret_value, buffer);
}

#ifdef DEBUG_ENABLED
Expand Down Expand Up @@ -161,11 +166,10 @@ void TransferContext::create_native_object(JNIEnv* p_raw_env, jobject p_instance

jni::Env env {p_raw_env};
TransferContext* transfer_context {GDKotlin::get_instance().transfer_context};
SharedBuffer* buffer {transfer_context->get_buffer(env)};

SharedBuffer* buffer {transfer_context->get_and_rewind_buffer(env)};
buffer->increment_position(encode_uint64(raw_ptr, buffer->get_cursor()));
buffer->increment_position(encode_uint64(id, buffer->get_cursor()));
buffer->rewind();
}

void TransferContext::get_singleton(JNIEnv* p_raw_env, jobject p_instance, jint p_class_index) {
Expand All @@ -174,10 +178,9 @@ void TransferContext::get_singleton(JNIEnv* p_raw_env, jobject p_instance, jint
)};
jni::Env env {p_raw_env};

SharedBuffer* buffer {GDKotlin::get_instance().transfer_context->get_buffer(env)};
SharedBuffer* buffer {GDKotlin::get_instance().transfer_context->get_and_rewind_buffer(env)};
buffer->increment_position(encode_uint64(reinterpret_cast<uintptr_t>(singleton), buffer->get_cursor()));
buffer->increment_position(encode_uint64(singleton->get_instance_id(), buffer->get_cursor()));
buffer->rewind();
}

void TransferContext::free_object(JNIEnv* p_raw_env, jobject p_instance, jlong p_raw_ptr) {
Expand All @@ -189,7 +192,3 @@ void TransferContext::free_object(JNIEnv* p_raw_env, jobject p_instance, jlong p

memdelete(owner);
}

void TransferContext::write_return_value(jni::Env& p_env, Variant& variant) {
write_return_value(get_buffer(p_env), variant);
}
9 changes: 1 addition & 8 deletions src/memory/transfer_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class TransferContext : public JavaInstanceWrapper {
static void free_object(JNIEnv* p_raw_env, jobject p_instance, jlong p_raw_ptr);

private:
SharedBuffer* get_buffer(jni::Env& p_env);
SharedBuffer* get_and_rewind_buffer(jni::Env& p_env);

_FORCE_INLINE_ static uint32_t read_args_size(SharedBuffer* buffer) {
uint32_t args_size {decode_uint32(buffer->get_cursor())};
Expand All @@ -46,13 +46,6 @@ class TransferContext : public JavaInstanceWrapper {
for (uint32_t i = 0; i < args_size; ++i) {
ktvariant::get_variant_from_buffer(buffer, p_args[i]);
}

buffer->rewind();
}

_FORCE_INLINE_ static void write_return_value(SharedBuffer* buffer, const Variant& r_ret) {
ktvariant::send_variant_to_buffer(r_ret, buffer);
buffer->rewind();
}

// clang-format off
Expand Down

0 comments on commit 41857e8

Please sign in to comment.