intrinsic that makes runtime choice whether to revert to java

Deneau, Tom tom.deneau at amd.com
Tue Jul 3 09:23:14 PDT 2012


Thanks you Vladimir.  Here is some background for others:

The goal here is to provide intrinsic routines which will make use of
a processor's AES instructions for processors that support those
instructions (the intrinsics also benefit from 128-bit wide xmm
registers which is the AES blocksize).  These intrinsics would replace
java routines in the default security provider found in
com.sun.crypto.provider.* when the crypto algorithm is AES.

I am sending this out to get feedback on the two different ways of
hooking in these intrinsics, and since one of the ways involves small
changes to the java classes in com.sun.crypto.provider, I am thus
copying jdk7-dev as well.

Using the crypto terminology of algorithm/mode/padding, the most
performant place to hook in is at the mode level (which handles
multiple blocks as opposed to the embeddedCipher's encryptBlock method
which handles a single block).  Thus for CBC mode the existing code in
com/sun/crypto/provider/CipherBlockChaining.java for encryption is the
following:

    void encrypt(byte[] plain, int plainOffset, int plainLen,
                 byte[] cipher, int cipherOffset)
    {
        int i;
        int endIndex = plainOffset + plainLen;

        for (; plainOffset < endIndex;
             plainOffset+=blockSize, cipherOffset += blockSize) {
            for (i=0; i<blockSize; i++) {
                k[i] = (byte)(plain[i+plainOffset] ^ r[i]);
            }
            embeddedCipher.encryptBlock(k, 0, cipher, cipherOffset);
            System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
        }
    }

and we would want to instrinsify this when the embeddedCipher is
instanceof AESCrypt.  

Here are the two basic choices for implementing this:

Option 1)
      The intrinsic would replace CipherBlockChaining.encrypt shown
      above, and as part of the intrinsic glue code would decide
      whether the embeddedCipher is of type AESCrypt and whether we
      meet any other requirements for intrinsifying.  If we pass the
      tests we call the intrinsic code, otherwise we call the code
      generated from the java bytecodes.  This is where the new
      callGenerator code from Vladimir comes in.  This choice would
      not require any modifications to the java classes, (although for
      a separate reason we would be changing the endianness of the
      expanded key as stored in the AESCrypt class).

Option 2)
      Slightly refactor a few of the com.sun.crypto.provider classes
      to that the above code is moved down into SymmetricCipher which
      is the base class of AESCrypt.  The new java code would look
      like the following with the intrinsic hooking into
      AESCrypt.encryptMultiBlockCBC:


========================================================================
CipherBlockChaining.java
------------------------
    void encrypt(byte[] plain, int plainOffset, int plainLen,
                 byte[] cipher, int cipherOffset)
    {
        // note that we pass a reference to our r array.
        embeddedCipher.encryptMultiBlockCBC(plain, plainOffset, plainLen, cipher, cipherOffset, r);
    }

SymmetricCipher.java
--------------------
    void encryptMultiBlockCBC(byte[] plain, int plainOffset, int plainLen,
                              byte[] cipher, int cipherOffset, byte[] r)
    {
        int i;
        int endIndex = plainOffset + plainLen;

        for (; plainOffset < endIndex;
             plainOffset+=blockSize, cipherOffset += blockSize) {
            for (i=0; i<blockSize; i++) {
                k[i] = (byte)(plain[i+plainOffset] ^ r[i]);
            }
            encryptBlock(k, 0, cipher, cipherOffset);
            System.arraycopy(cipher, cipherOffset, r, 0, blockSize);
        }
    }

AESCrypt.java
-------------
final class AESCrypt extends SymmetricCipher implements AESConstants
{
 ....
    @Override
    void encryptMultiBlockCBC(byte[] plain, int plainOffset, int plainLen,
                              byte[] cipher, int cipherOffset, byte[] r)
    {
        // provides a point for an AESCrypt intrinsic to hook in
        // but if not intrinsified, just does the default provided by SymmetricCipher
        super.encryptMultiBlockCBC(plain, plainOffset, plainLen, cipher, cipherOffset, r);
    }

====================================================================

The above choices would apply to other modes like ECB, etc. if we want
to intrinsify them.

-- Tom 

-----Original Message-----
From: Vladimir Kozlov [mailto:vladimir.kozlov at oracle.com] 
Sent: Monday, July 02, 2012 9:57 PM
To: Deneau, Tom
Cc: hotspot-compiler-dev at openjdk.java.net
Subject: Re: intrinsic that makes runtime choice whether to revert to java

I finally had time today to look on this. Here is code:

http://cr.openjdk.java.net/~kvn/pred_intr/webrev

But I did not test or optimize it (part of new code in callGenerator.cpp should 
be shared with PredictedCallGenerator from which it was cloned).

Vladimir

Deneau, Tom wrote:
> Hi all --
> 
> I am writing a hotspot intrinsic but I want it to make a runtime
> choice whether to execute the intrinsic code or to execute the regular
> java code.
> 
> I got the suggestion below from Vladimir but I am not experienced
> enough with the graphkit functionality to see how to do this.  Would
> someone be able to provide the code skeleton for this?  I can generate
> the region to actually do my intrinsic and I believe I can generate the
> BoolNode which determines which path to take.
> 
> The other choice would be to modify the actual JDK library routine to
> do the runtime tests and call a new routine which the intrinsic would
> hook into.  I have done this for testing but I am assuming this is more
> intrusive since on some architectures the intrinsic will not even be generated.
> 
> -- Tom Deneau
> 
>> We don't have such mechanism currently. But it is not difficult to implement. 
>> Look on the code in doCall.cpp and callGenerator files. Instead of calling 
>> find_intrinsic() you need to do something special for your case. Like code for 
>> CallGenerator::for_method_handle_call() where you will generate class check and 
>> on one path you will get intrinsic (by calling find_intrinsic()) and on other 
>> path is regular CallGenerator::for_inline().
> 
> 




More information about the hotspot-compiler-dev mailing list