--- a/src/hotspot/share/opto/library_call.cpp Fri Aug 16 14:46:52 2019 -0400
+++ b/src/hotspot/share/opto/library_call.cpp Fri Aug 16 14:42:50 2019 -0700
@@ -293,8 +293,10 @@
bool inline_Class_cast();
bool inline_aescrypt_Block(vmIntrinsics::ID id);
bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id);
+ bool inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id);
bool inline_counterMode_AESCrypt(vmIntrinsics::ID id);
Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting);
+ Node* inline_electronicCodeBook_AESCrypt_predicate(bool decrypting);
Node* inline_counterMode_AESCrypt_predicate();
Node* get_key_start_from_aescrypt_object(Node* aescrypt_object);
Node* get_original_key_start_from_aescrypt_object(Node* aescrypt_object);
@@ -807,6 +809,10 @@
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
return inline_cipherBlockChaining_AESCrypt(intrinsic_id());
+ case vmIntrinsics::_electronicCodeBook_encryptAESCrypt:
+ case vmIntrinsics::_electronicCodeBook_decryptAESCrypt:
+ return inline_electronicCodeBook_AESCrypt(intrinsic_id());
+
case vmIntrinsics::_counterMode_AESCrypt:
return inline_counterMode_AESCrypt(intrinsic_id());
@@ -912,6 +918,10 @@
return inline_cipherBlockChaining_AESCrypt_predicate(false);
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
return inline_cipherBlockChaining_AESCrypt_predicate(true);
+ case vmIntrinsics::_electronicCodeBook_encryptAESCrypt:
+ return inline_electronicCodeBook_AESCrypt_predicate(false);
+ case vmIntrinsics::_electronicCodeBook_decryptAESCrypt:
+ return inline_electronicCodeBook_AESCrypt_predicate(true);
case vmIntrinsics::_counterMode_AESCrypt:
return inline_counterMode_AESCrypt_predicate();
case vmIntrinsics::_digestBase_implCompressMB:
@@ -6019,6 +6029,94 @@
return true;
}
+//------------------------------inline_electronicCodeBook_AESCrypt-----------------------
+bool LibraryCallKit::inline_electronicCodeBook_AESCrypt(vmIntrinsics::ID id) {
+ address stubAddr = NULL;
+ const char *stubName = NULL;
+
+ assert(UseAES, "need AES instruction support");
+
+ switch (id) {
+ case vmIntrinsics::_electronicCodeBook_encryptAESCrypt:
+ stubAddr = StubRoutines::electronicCodeBook_encryptAESCrypt();
+ stubName = "electronicCodeBook_encryptAESCrypt";
+ break;
+ case vmIntrinsics::_electronicCodeBook_decryptAESCrypt:
+ stubAddr = StubRoutines::electronicCodeBook_decryptAESCrypt();
+ stubName = "electronicCodeBook_decryptAESCrypt";
+ break;
+ default:
+ break;
+ }
+
+ if (stubAddr == NULL) return false;
+
+ Node* electronicCodeBook_object = argument(0);
+ Node* src = argument(1);
+ Node* src_offset = argument(2);
+ Node* len = argument(3);
+ Node* dest = argument(4);
+ Node* dest_offset = argument(5);
+
+ // (1) src and dest are arrays.
+ const Type* src_type = src->Value(&_gvn);
+ const Type* dest_type = dest->Value(&_gvn);
+ const TypeAryPtr* top_src = src_type->isa_aryptr();
+ const TypeAryPtr* top_dest = dest_type->isa_aryptr();
+ assert(top_src != NULL && top_src->klass() != NULL
+ && top_dest != NULL && top_dest->klass() != NULL, "args are strange");
+
+ // checks are the responsibility of the caller
+ Node* src_start = src;
+ Node* dest_start = dest;
+ if (src_offset != NULL || dest_offset != NULL) {
+ assert(src_offset != NULL && dest_offset != NULL, "");
+ src_start = array_element_address(src, src_offset, T_BYTE);
+ dest_start = array_element_address(dest, dest_offset, T_BYTE);
+ }
+
+ // if we are in this set of code, we "know" the embeddedCipher is an AESCrypt object
+ // (because of the predicated logic executed earlier).
+ // so we cast it here safely.
+ // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java
+
+ Node* embeddedCipherObj = load_field_from_object(electronicCodeBook_object, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false);
+ if (embeddedCipherObj == NULL) return false;
+
+ // cast it to what we know it will be at runtime
+ const TypeInstPtr* tinst = _gvn.type(electronicCodeBook_object)->isa_instptr();
+ assert(tinst != NULL, "ECB obj is null");
+ assert(tinst->klass()->is_loaded(), "ECB obj is not loaded");
+ ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt"));
+ assert(klass_AESCrypt->is_loaded(), "predicate checks that this class is loaded");
+
+ ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass();
+ const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt);
+ const TypeOopPtr* xtype = aklass->as_instance_type();
+ Node* aescrypt_object = new CheckCastPPNode(control(), embeddedCipherObj, xtype);
+ aescrypt_object = _gvn.transform(aescrypt_object);
+
+ // we need to get the start of the aescrypt_object's expanded key array
+ Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
+ if (k_start == NULL) return false;
+
+ Node* ecbCrypt;
+ if (Matcher::pass_original_key_for_aes()) {
+ // no SPARC version for AES/ECB intrinsics now.
+ return false;
+ }
+ // Call the stub, passing src_start, dest_start, k_start, r_start and src_len
+ ecbCrypt = make_runtime_call(RC_LEAF | RC_NO_FP,
+ OptoRuntime::electronicCodeBook_aescrypt_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ src_start, dest_start, k_start, len);
+
+ // return cipher length (int)
+ Node* retvalue = _gvn.transform(new ProjNode(ecbCrypt, TypeFunc::Parms));
+ set_result(retvalue);
+ return true;
+}
+
//------------------------------inline_counterMode_AESCrypt-----------------------
bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) {
assert(UseAES, "need AES instruction support");
@@ -6215,6 +6313,65 @@
return _gvn.transform(region);
}
+//----------------------------inline_electronicCodeBook_AESCrypt_predicate----------------------------
+// Return node representing slow path of predicate check.
+// the pseudo code we want to emulate with this predicate is:
+// for encryption:
+// if (embeddedCipherObj instanceof AESCrypt) do_intrinsic, else do_javapath
+// for decryption:
+// if ((embeddedCipherObj instanceof AESCrypt) && (cipher!=plain)) do_intrinsic, else do_javapath
+// note cipher==plain is more conservative than the original java code but that's OK
+//
+Node* LibraryCallKit::inline_electronicCodeBook_AESCrypt_predicate(bool decrypting) {
+ // The receiver was checked for NULL already.
+ Node* objECB = argument(0);
+
+ // Load embeddedCipher field of ElectronicCodeBook object.
+ Node* embeddedCipherObj = load_field_from_object(objECB, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false);
+
+ // get AESCrypt klass for instanceOf check
+ // AESCrypt might not be loaded yet if some other SymmetricCipher got us to this compile point
+ // will have same classloader as ElectronicCodeBook object
+ const TypeInstPtr* tinst = _gvn.type(objECB)->isa_instptr();
+ assert(tinst != NULL, "ECBobj is null");
+ assert(tinst->klass()->is_loaded(), "ECBobj is not loaded");
+
+ // we want to do an instanceof comparison against the AESCrypt class
+ ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt"));
+ if (!klass_AESCrypt->is_loaded()) {
+ // if AESCrypt is not even loaded, we never take the intrinsic fast path
+ Node* ctrl = control();
+ set_control(top()); // no regular fast path
+ return ctrl;
+ }
+ ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass();
+
+ Node* instof = gen_instanceof(embeddedCipherObj, makecon(TypeKlassPtr::make(instklass_AESCrypt)));
+ Node* cmp_instof = _gvn.transform(new CmpINode(instof, intcon(1)));
+ Node* bool_instof = _gvn.transform(new BoolNode(cmp_instof, BoolTest::ne));
+
+ Node* instof_false = generate_guard(bool_instof, NULL, PROB_MIN);
+
+ // for encryption, we are done
+ if (!decrypting)
+ return instof_false; // even if it is NULL
+
+ // for decryption, we need to add a further check to avoid
+ // taking the intrinsic path when cipher and plain are the same
+ // see the original java code for why.
+ RegionNode* region = new RegionNode(3);
+ region->init_req(1, instof_false);
+ Node* src = argument(1);
+ Node* dest = argument(4);
+ Node* cmp_src_dest = _gvn.transform(new CmpPNode(src, dest));
+ Node* bool_src_dest = _gvn.transform(new BoolNode(cmp_src_dest, BoolTest::eq));
+ Node* src_dest_conjoint = generate_guard(bool_src_dest, NULL, PROB_MIN);
+ region->init_req(2, src_dest_conjoint);
+
+ record_for_igvn(region);
+ return _gvn.transform(region);
+}
+
//----------------------------inline_counterMode_AESCrypt_predicate----------------------------
// Return node representing slow path of predicate check.
// the pseudo code we want to emulate with this predicate is: