Recent Posts
Archives

Posts Tagged ‘KotlinNative’

PostHeaderIcon [KotlinConf2025] The Life and Death of a Kotlin Native Object

The journey of an object within a computer’s memory is a topic that is often obscured from the everyday developer. In a highly insightful session, Troels Lund, a leader on the Kotlin/Native team at Google, delves into the intricacies of what transpires behind the scenes when an object is instantiated and subsequently discarded within the Kotlin/Native runtime. This detailed examination provides a compelling look at a subject that is usually managed automatically, demonstrating the sophisticated mechanisms at play to ensure efficient memory management and robust application performance.

The Inner Workings of the Runtime

Lund begins by exploring the foundational elements of the Kotlin/Native runtime, highlighting its role in bridging the gap between high-level Kotlin code and the native environment. The runtime is responsible for a variety of critical tasks, including memory layout, garbage collection, and managing object lifecycles. One of the central tenets of this system is its ability to handle memory allocation and deallocation with minimal developer intervention. The talk illustrates how an object’s structure is precisely defined in memory, a crucial step for both performance and predictability. This low-level perspective offered a new appreciation for the seamless operation that developers have come to expect.

A Deep Dive into Garbage Collection

The talk then progresses to the sophisticated mechanisms of garbage collection. A deep dive into the Kotlin/Native memory model reveals a system designed for both performance and concurrency. Lund describes the dual approach of a parallel mark and concurrent sweep and a concurrent mark and sweep. The parallel mark and concurrent sweep is designed to maximize throughput by parallelizing the marking phase, while the concurrent mark and sweep aims to minimize pause times by allowing the sweeping phase to happen alongside application execution. The session details how these processes identify and reclaim memory from objects that are no longer in use, preventing memory leaks and maintaining system stability. The discussion also touches upon weak references and their role in memory management. Lund explains how these references are cleared out in a timely manner, ensuring that objects that should be garbage-collected are not resurrected.

Final Thoughts on the Runtime

In his concluding remarks, Lund offers a final summary of the Kotlin/Native runtime. He reiterates that this is a snapshot of what is happening now, and that the details are subject to change over time as new features are added and existing ones are optimized. He emphasizes that the goal of the team is to ensure that the developer experience is as smooth and effortless as possible, with the intricate details of memory management handled transparently by the runtime. The session serves as a powerful reminder of the complex engineering that underpins the simplicity and elegance of the Kotlin language, particularly in its native context.

Links:

PostHeaderIcon [KotlinConf2025] Dependencies and Kotlin Native

The world of dependency management is often taken for granted in the JVM ecosystem. However, when venturing into the realm of Kotlin Native, the familiar comforts of JAR files and class loaders fade, giving way to a more intricate and challenging landscape. In his insightful talk, Tadeas Kriz, a senior Kotlin developer at Touchlab, demystified this complex topic, offering a detailed comparison between JVM and native dependency handling and providing practical solutions for common issues.

Tadeas began by drawing a clear distinction between the two worlds. The JVM handles the heavy lifting of linking and loading dependencies at runtime, a process that is largely transparent to the developer. In contrast, Kotlin Native produces a standalone binary, which means the developer must contend with the nuances of native linking and compilation. This fundamental difference introduces a new set of challenges, particularly for those accustomed to the JVM’s seamless “it just works” experience.

He delved into the specifics of native platforms, examining dependency management tools like CocoaPods and Swift Package Manager used on Apple platforms. By comparing their strengths and weaknesses, Tadeas provided valuable context for how Kotlin Multiplatform fits into this ecosystem. He underscored the importance of understanding the native build process, a step that is often abstracted away but is crucial for troubleshooting the cryptic errors that can arise when integrating dependencies. He emphasized that static linking is often the most reliable approach in Kotlin Native, offering a more predictable and robust solution.

A significant portion of the talk was dedicated to practical workarounds and tools to overcome these challenges. Tadeas introduced a key concept: cinterop bindings, which are used to interact with C libraries from Kotlin Native code. He explained how to handle dynamic and static libraries and provided guidance on navigating the complexities of header file inclusion and symbol visibility. He also highlighted the utility of specific tools and practices, such as meticulously heeding build warnings, as they often contain clues to underlying issues.

Tadeas also brought attention to Skie, an open-source tool he co-authored, which addresses a key pain point for developers: the quality of the Kotlin Multiplatform API exposed to Swift. He explained that Skie enhances the generated Swift API, making it more idiomatic and easier for iOS developers to work with. He positioned it as a valuable solution for teams looking to improve their development workflow and collaboration while waiting for future features like Swift export. His talk provided a comprehensive guide, arming developers with the knowledge and tools needed to navigate the complexities of dependencies in the Kotlin Native world with greater confidence and efficiency.

Links:


PostHeaderIcon [KotlinConf2025] Building a macOS Screen Saver with Kotlin

A captivating tale of a developer’s obsession and a journey into the less-trodden paths of Kotlin development was shared by Márton Braun, a Developer Advocate at JetBrains. It all began with a simple, yet compelling, observation at a previous KotlinConf: a screen saver featuring the bouncing Kotlin logos, reminiscent of old DVD players. Upon discovering it was merely a pre-rendered video and not a true screen saver, a challenge was born. Márton set out to build his own, a native macOS application powered by Kotlin/Native.

The project became a masterclass in interoperability and a candid exploration of the quirks of native application development. Márton detailed how Kotlin/Native’s powerful interop capabilities made it surprisingly easy to call native macOS APIs. However, this ease was often contrasted with the complexities and frustrations of working with the macOS platform itself. The development process was a constant battle, with macOS often proving to be an uncooperative partner in this creative endeavor.

Márton’s perseverance paid off, resulting in a fully functional screen saver. He even managed to create two distinct implementations: one using the traditional AppKit framework and another built with Compose Multiplatform. This dual approach not only demonstrated the capabilities of both technologies but also provided a unique learning experience. He highlighted how the Compose version allowed him to focus on the core UI logic, abstracting away the intricacies of packaging the screen saver. This is a powerful testament to Compose Multiplatform’s potential for simplifying development and improving productivity.

The screen saver project serves as an excellent case study, showcasing Kotlin’s ability to venture into unconventional domains beyond mobile and backend development. Márton successfully demonstrated that with Kotlin and the right tools, developers can create truly native applications for platforms like macOS, leveraging their existing skills and knowledge. The flexibility of Kotlin Multiplatform allows developers to share code across platforms while still delivering a native user experience.

Ultimately, this project is a celebration of the unique possibilities that Kotlin offers. It encourages developers to think creatively about how they can apply the language to solve a wide range of problems and build applications for a diverse set of platforms. Márton’s story is an inspiring reminder that sometimes the most interesting and valuable projects are born from a simple desire to see something that doesn’t exist yet come to life.

Links:


PostHeaderIcon [KotlinConf2023] Video Game Hacking with Kotlin/Native: A Low-Level Adventure with Ignat Beresnev

At KotlinConf’23, Ignat Beresnev, a member of the Kotlin team at JetBrains and a core contributor to Dokka, stepped onto the stage with an unexpected topic: using Kotlin/Native for video game hacking. Far from a gimmick, his talk offered a solid foundation in low-level memory manipulation techniques, revealing how Kotlin/Native can be a surprisingly practical tool for creating trainers, bots, and various forms of game hacks. Drawing on examples such as modding Grand Theft Auto, the session aimed to demystify game hacking and present it as an accessible and technically rich domain for Kotlin developers.

Ignat began by recounting his personal journey into game modification, which started years earlier with a self-imposed challenge to write a World of Warcraft bot in Java. While technically successful, the attempt exposed the limitations of Java when it comes to low-level system access. Rediscovering the problem through the lens of Kotlin/Native, he found a much better fit: a language that retained Kotlin’s expressiveness while unlocking native-level capabilities required for deep interaction with operating system APIs.

Understanding Game Internals and Memory Manipulation

The core premise of game hacking, Ignat explained, lies in understanding how games store and manage state. Just like any other program, a game keeps its data—such as player health, in-game currency, or positional coordinates—in memory. If you can discover where a particular value is stored, you can read it, monitor it, or even modify it in real time. He illustrated this with a relatable scenario: if a character in a game has 100 units of currency, then somewhere in memory exists a variable holding that value. The trick is finding it.

To pinpoint such a memory address, one typically uses a memory scanning tool like Cheat Engine. The process involves searching the memory space for a known value—say, 100—then performing an in-game action that changes it, such as spending money. The search is then repeated for the new value (e.g., 80), gradually narrowing down the list of candidate addresses until the correct one is isolated.

Once the memory address is identified, Kotlin/Native can be used to read from or write to that memory location by interfacing directly with native Windows API functions. Ignat detailed this workflow by first obtaining a handle to the target process using functions like OpenProcess, which grants the required permissions to access another process’s memory. He pointed out how abstract and opaque some of the types in C APIs can be—such as HANDLE, which is essentially a pointer behind the scenes—but noted that Kotlin/Native handles these seamlessly through its C interop layer.

To read memory, one would use ReadProcessMemory, specifying the process handle, the target memory address, a buffer to receive the data, and additional arguments to track the number of bytes read. Kotlin/Native’s support for functions like allocArray and cValuesOf simplifies this otherwise complex operation. Writing memory involves a nearly identical process, this time using the WriteProcessMemory function to inject new values into specific memory locations.

Ignat added a humorous aside, noting how tricky it can be to locate something like a string literal in a game’s memory. Nonetheless, he successfully demonstrated a live example, changing an on-screen number in a lightweight game to prove the concept in action.

DLL Injection and Function Invocation

While reading and writing memory opens up powerful capabilities, more advanced techniques allow even deeper integration with the target game. One such technique is DLL injection. This method involves writing a Dynamic Link Library and tricking the game process into loading it. Once loaded, the DLL gains access to the same memory and execution privileges as the game itself, effectively becoming part of its runtime.

Ignat outlined the injection process step by step. First, the target process must be located and a handle acquired. Next, the injector allocates memory in the target’s address space to store the path of the DLL. This path is written into the allocated space, after which the program looks up the address of the LoadLibrary function in kernel32.dll. Since this system library is mapped at the same location across processes, it provides a reliable anchor point. Finally, CreateRemoteThread is used to spawn a new thread inside the game process that calls LoadLibrary, thereby loading the malicious DLL and executing its code.

Once injected, the DLL has full access to call the game’s internal functions—if their memory addresses and calling conventions are known. Ignat demonstrated this by referencing documentation from a modding community for GTA: San Andreas, which includes reverse-engineered addresses and function signatures for in-game routines like CreateCar. By defining a function pointer in Kotlin/Native that matches the signature and calling it through the injected DLL, one can trigger effects like spawning vehicles at will. Of course, this requires careful adherence to calling conventions, such as stdcall, and a deep understanding of binary interfaces.

Beyond Games: Broader Applications

While the talk focused on game modification, Ignat was clear in emphasizing that these techniques extend far beyond entertainment. The same approaches can be used to patch bugs in native libraries, build plugins for applications not originally designed for extensibility, gather usage metrics from legacy software, or automate GUI interactions. What Kotlin/Native brings to the table is the rare combination of modern Kotlin syntax with native-level system access, making it a uniquely powerful tool for developers interested in systems programming, reverse engineering, or unconventional automation.

By the end of the session, Ignat had shown not just how to hack a game, but how to think like a systems programmer using Kotlin/Native. It was a fascinating, fun, and deeply technical presentation that pushed the boundaries of what most Kotlin developers might expect from their tooling—and opened the door to new realms of possibility.

Links:

PostHeaderIcon [KotlinConf2019] Kotlin Multiplatform Programming: Present and Future with Dmitry Savvinov and Liliia Abdulina

Kotlin Multiplatform Programming (MPP) has been a significant focus for JetBrains, aiming to extend Kotlin’s reach beyond traditional JVM and Android development. At KotlinConf 2019, Dmitry Savvinov and Liliia Abdulina, both from the Kotlin team at JetBrains, delivered an insightful overview of MPP’s capabilities in version 1.3.X and offered a glimpse into its future direction. Dmitry Savvinov, a key contributor to Kotlin Contracts and heavily involved in MPP, brought his compiler expertise to the discussion. The official Kotlin language website, the central hub for MPP information, is kotlinlang.org.

Their talk was structured to cover the fundamentals of multiplatform projects, illustrate these basics with examples, provide guidelines for designing first multiplatform projects, and showcase a production-like application to demonstrate design principles in action. This comprehensive approach aimed to equip developers with the knowledge needed to start leveraging MPP effectively.

Core Concepts of Kotlin Multiplatform

Dmitry Savvinov and Liliia Abdulina began by explaining the core building blocks of Kotlin Multiplatform projects. These foundational concepts are crucial for understanding how code can be shared and specialized across different platforms:
* Source Sets: The fundamental unit of code organization in MPP. A project is typically structured with a commonMain source set containing platform-agnostic Kotlin code. Platform-specific source sets (e.g., jvmMain, jsMain, iosMain) contain code tailored for each target and can depend on commonMain.
* Targets: These define the platforms the project will compile for, such as JVM, Android, JavaScript, iOS (Native), Linux, Windows, and macOS. Each target has its own compilations.
* Compilations: A compilation process for a specific target that produces the appropriate artifacts (e.g., JVM bytecode, JavaScript files, native executables).
* expect and actual Declarations: This powerful mechanism allows common code in commonMain to declare an expect class, function, or property. Platform-specific source sets must then provide an actual implementation for that declaration, bridging the gap between shared logic and platform-specific APIs. For example, a common module might expect a function to generate a UUID, and the JVM and Native modules would provide actual implementations using their respective platform libraries.

These concepts enable developers to write shared business logic, data models, and algorithms once in commonMain and then reuse them across multiple platforms, significantly reducing code duplication and improving consistency.

Designing and Implementing Multiplatform Projects

Beyond the basic syntax, Dmitry and Liliia provided guidance on how to approach the design of a multiplatform project. This involved discussing strategies for identifying what code can and should be shared, how to structure modules for optimal maintainability, and best practices for using expect/actual effectively.

They used toy examples to illustrate these basics in a clear and understandable manner, helping attendees grasp how these pieces fit together in a real project. The presentation then progressed to showcase a “more or less production-like application”. This larger example would have served to demonstrate how the design principles discussed could be applied to build a substantial, real-world multiplatform application, highlighting how to manage dependencies, handle platform-specific interactions, and structure a scalable MPP architecture. The focus was on providing practical insights that developers could apply to their own projects, whether starting from scratch or integrating MPP into existing applications.

The Trajectory of Kotlin Multiplatform: Beyond 1.3.X

While detailing the state of MPP in Kotlin 1.3.X, Dmitry Savvinov and Liliia Abdulina also looked towards its future development. At KotlinConf 2019, MPP was still evolving, with ongoing improvements to tooling, library support, and the overall developer experience. Their talk touched upon the roadmap for MPP, including planned enhancements to areas like Kotlin/Native (for performance and interoperability), library ecosystem growth, and further refinements to the build system and IDE support within IntelliJ IDEA and Android Studio.

The vision presented was one of Kotlin as a truly universal language, enabling developers to target a wide array of platforms with a unified codebase and skillset. The commitment from JetBrains to invest heavily in MPP was clear, with the aim of making it a robust and production-ready solution for cross-platform development. The session would have encouraged developers to explore MPP, provide feedback, and contribute to its growing ecosystem, reinforcing the community-driven aspect of Kotlin’s development.

Links: