Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
Disclaimers: - Iâll use Windows and more particularly Visual C++ with its Inline Assembler. If you use MacOs or Linux you will have significant differences comparing to what is described in the article.- Everything below is shown mostly for demonstration purposes
Introduction
Java is mature self-sufficient language, though as we all know it is possible to âconnectâ java to C (via Java-Native-Interface or JNI) to speed up some critical pieces of code.Also for C/C++ it is possible to delegate some even more critical pieces of code directly to Assembly.
In this article I want to show you how this Java-C-Assembly Matryoshka can look like. But note that example will be pretty simple so in real world there is no advantage of such delegation as it wonât speed up anything.
The example weâll look at will be:
- given a command line program (written in Java)
- we execute the program with providing 2 integers as arguments (with error handling on the client side)
- main business logic is the âsumâ method, which we consider a critical piece of the program weâd like to âspeed upâ using C and Assembly.
Java
Setup
First of all we need to download JDK.I have pretty old version installed, but feel free to install newer version.After installation verify that everything works:
>java -versionjava version "1.8.0_121"Java(TM) SE Runtime Environment (build 1.8.0_121-b13)Java HotSpot(TM) Client VM (build 25.121-b13, mixed mode, sharing)
Code
Here is our program: main function, parsing command line arguments and our target method âsumâ (with implementation in java):
public class Test { public static void main(String[] args) { if (args.length != 2) { System.out.println("Error: wrong params count"); return; } int a; try { a = Integer.parseInt(args[0]); } catch (Throwable throwable) { System.out.println("First param is not a number"); return; } int b; try { b = Integer.parseInt(args[1]); } catch (Throwable throwable) { System.out.println("Second param is not a number"); return; } Test test = new Test(); System.out.println(test.sum(a, b)); } public static int sum(int a, int b) { return a + b; }}
Compile
In order to run the program we first need to compile it with java compiler. It will generate Test.class binary file which weâll later on execute.
> javac Test.java
Execute
To execute program call java and provide arguments. See that our program works correctly and prints sum of numbers.
> java Test 3 47
C/JNI
Setup
Install Chocolatey and using it install Visual C++ build tools:
choco install visualcpp-build-tools
Weâll need these tools to compile C files into library dll file. Specifically for compilation weâll need cl command, so check that it works:
>clMicrosoft (R) C/C++ Optimizing Compiler Version 19.16.27031.1 for x86Copyright (C) Microsoft Corporation. All rights reserved.
Code
Java can communicate with C via JNI. In order to setup that communication we need to update our Java program:
public class Test { public static void main(String[] args) { if (args.length != 2) { System.out.println("Error: wrong params count"); return; } int a; try { a = Integer.parseInt(args[0]); } catch (Throwable throwable) { System.out.println("First param is not a number"); return; } int b; try { b = Integer.parseInt(args[1]); } catch (Throwable throwable) { System.out.println("Second param is not a number"); return; }
System.loadLibrary("Test");Test test = new Test(); System.out.println(test.sum(a, b)); }public native int sum(int a, int b);}
First, instead of static method with implementation we provide so called native method. It doesnât have any implementation because we expect it to be provided via JNI. Second, we need to load our C libraryâââand we do that with System.loadLibrary method.
After we updated our program we need to generate Test.h header file:
> javah Test
Generated header file will contain all the setup for our C program. We had one native method in our Java program and here we have method declaration for our method generated in header file:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class Test */
#ifndef _Included_Test#define _Included_Test#ifdef __cplusplusextern "C" {#endif/* * Class: Test * Method: sum * Signature: (II)I */JNIEXPORT jint JNICALL Java_Test_sum (JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus}#endif#endif
We need to have an implementation of our function, so create Test.c file and implement method:
#include "Test.h"
JNIEXPORT jint JNICALL Java_Test_sum (JNIEnv *env, jobject obj, jint a, jint b) { return a + b; }
void main() {}
Compile
Compile our C library into Test.dll:
> cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD Test.c -FeTest.dll
Execute
Recompile our Java program as shown above and execute to see that it still works:
> java Test 3 47
Assembly
Code
Previously we had C implementation which looked basically as on java: a + b. When we work with Assembly we work on a lower level so such small operations require quite more code.Letâs update our C program to use Assemblyâââfor this we add __asm blockâââwhich is Inline Assembler for Visual C++.Inside that block we write instructions. You see that we put our variable a into register eax, put our variable b into register ebx. Then we make a sum from contents of registers and store it in the eax register (this is what add command does).Lastly we store value of the eax register in our result field:
#include "Test.h"#include <stdio.h>
JNIEXPORT jint JNICALL Java_Test_sum (JNIEnv *env, jobject obj, jint a, jint b) { int result; __asm { mov eax, a mov ebx, b add eax, ebx mov result, eax } return result;}
void main() {}
Recompile C library (no need to recompile Java program) and execute Java program again:
> java Test 3 47
So, it works.
Hope youâve enjoyed and maybe learned something today. If not then I hope at least it was funny.
Happy coding!
References:
- javac - Java programming language compiler
- Guide to JNI (Java Native Interface) | Baeldung
- Inline Assembler
Java-C-Assembly Matryoshka was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.