0

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?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
User1291
  • 7,664
  • 8
  • 51
  • 108
  • Although the `$` character is technically permitted in field names, as a matter of good style, *please* do not use it. – John Bollinger Nov 13 '17 at 15:42
  • @JohnBollinger it's a benchmark, testing the kind of code that (or something similar) will later be generated and automatically added to classes at compile-time. using ``$`` is an easy way to prevent naming conflicts. – User1291 Nov 13 '17 at 15:44
  • That doesn't mean you need to subject us to it. It behooves you to make your question as easy on *us* as possible. – John Bollinger Nov 13 '17 at 16:02
  • Anyway, the question confuses me. At first you seem to be asking about using `sun.misc.Unsafe` via JNI, but then you change and seem to be asking how to implement a workalike. Which is it? – John Bollinger Nov 13 '17 at 16:06
  • @JohnBollinger I'd prefer not to have to make that callback into java, if at all possible. – User1291 Nov 13 '17 at 16:15
  • I'm afraid there is no documented API for obtaining the (virtual) address of the storage for a field's value. The details are likely to vary between VM implementations, and possibly even between different versions of the same implementation. If you want to pursue this route then your best bet is probably to look at the implementation of `sun.misc.Unsafe` on the VM(s) of interest to see how they do it. – John Bollinger Nov 13 '17 at 16:30
  • @JohnBollinger funny you should mention that, because that's what I'm currently doing... or trying to, at least, see https://stackoverflow.com/questions/47267806/substituting-jvm-oop-pointer-in-c – User1291 Nov 13 '17 at 16:35
  • Well, no, actually, it looks like what you're poking into in your other question is the implementation of the JVM. It is possible that you'll eventually end up there anyway, but the implementation of (the native parts of) class `sun.misc.Unsafe` should provide better context. – John Bollinger Nov 13 '17 at 16:45

0 Answers0