How to use “unsafe” in JNI?

前提是你 提交于 2019-12-20 05:52:09

问题


Let's say I have a value pointed to by a (base,offset) tuple.

e.g.

class Data{
    int x = 0;
}

class Accessor{
    public Data data;
    public Object base$x;
    public long off$x;
    public static final Unsafe unsafe;

    public void run(){
        data = new Data();

        base$x = data;
        off$x = 12;
        unsafe.putInt(base$x,off$x,1);

        assert(data.x == 1);
    }

    static{
        try {
            Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
            unsafeConstructor.setAccessible(true);
            unsafe = unsafeConstructor.newInstance();
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) {
            throw new RuntimeException(e);
        }
    }
}

(runnable version: https://ideone.com/OasQrh )

I now want to execute

unsafe.setInt(base$x,off$x,1);

in C.

Why? Because a different process may move the data and changebase and off to point to the new location. I want to make use of intel RTM to make sure moving the data does not interfere with regular accesses to the field.

So let's create a new class

class Transactionally{
     static{
         System.loadLibrary("RTM_transact");
     }
     public static native void setInt(Object target, String fieldname);
}

and replace

class Accessor{
    public Data data;
    public Object base;
    public long off;
    public static final Unsafe unsafe;

    public void run(){
        data = new Data();

        base$x = data;
        off$x = 12;

        Transactionally.setInt(this,"x",1);

        assert(data.x == 1);
    }

    static{
        try {
            Constructor<Unsafe> unsafeConstructor = Unsafe.class.getDeclaredConstructor();
            unsafeConstructor.setAccessible(true);
            unsafe = unsafeConstructor.newInstance();
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) {
            throw new RuntimeException(e);
        }
    }
}

we run this through javah to get the header, copy the method signatures to an RTM_transct.cpp and get something like

#include<jni.h>
#include "rtmbenchmark_Transactionally.h"
#include <string>

std::string fldBase("base$");
std::string fldOff("off$");

/*
* Class:     rtmbenchmark_Transactionally
* Method:    setInt
* Signature: (Ljava/lang/Object;Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL Java_rtmbenchmark_Transactionally_setInt(JNIEnv *env, jclass _obsolete, jobject target, jstring fieldname, jint value){
    jclass targetClass = (*env)->GetObjClass(env,target);
    jfieldID fidFLDbase = (*env)->GetFieldID(env, targetClass, fldBase + fieldname, "Ljava.lang.Object");
    jfieldid fidFLDoff = (*env)->GetFieldID(env, targetClass, fldOff + fieldname, "J");


    volatile int tries = 0;
    volatile boolean success = 0;
    while(!success){/*TODO: maybe switch to a different strategy when tries grows too large?*/
        __asm__ __volatile__ (
            "xbegin 1f" /*1f: local label 1, look forward to find first*/
                :"+rm"(tries) /*artificial dependency to prevent re-ordering*/
        );
        ++tries;

        jobject base = (*env)->GetIntField(env,targetClass,fidFLDbase);
        jlong offset = (*env)->GetLongField(env,targetClass,fidFLDoff);
        //??? ==> unsafe.setLong(base,offset,value)

        __asm__ __volatile__ (
            "xend\n\t"
            "incl %0\n" /*increment success ==> break out of loop*/
            "jmp 2f\n" /*jump to end of loop*/
            "1:\n\t" /*local label 1 (jumped to when transaction is aborted)*/
            "2:" /*local label 2 (jumped to after transaction succeeded)*/
            :"+rm"(success)
            :"rm"(tries) /*artificial dependency*/
        );
    }
}

What do I use for unsafe, in the transaction body?

The "heart" of the transaction are these three lines that (are supposed to) correspond to what Accessor used to do:

        jobject base = (*env)->GetIntField(env,targetClass,fidFLDbase);
        jlong offset = (*env)->GetLongField(env,targetClass,fidFLDoff);
        //??? ==> unsafe.setInt(base,offset,value)

)

Ideally, of course, I'd like to do something akin to base[offset] = value, but I very much doubt that would work.

What do I put here for unsafe.setInt?

来源:https://stackoverflow.com/questions/47220275/how-to-use-unsafe-in-jni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!