aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm
diff options
context:
space:
mode:
authorkvn <none@none>2012-10-24 14:33:22 -0700
committerkvn <none@none>2012-10-24 14:33:22 -0700
commitf1d6dc261e69a36e094118451f35c7f90b5fc7e1 (patch)
tree5f7dd4cb0f737345255d2abea1536834c2c63439 /src/share/vm
parented5447be6be3e258e9fc9e4892db615340177731 (diff)
7184394: add intrinsics to use AES instructions
Summary: Use new x86 AES instructions for AESCrypt. Reviewed-by: twisti, kvn, roland Contributed-by: tom.deneau@amd.com
Diffstat (limited to 'src/share/vm')
-rw-r--r--src/share/vm/classfile/vmSymbols.hpp16
-rw-r--r--src/share/vm/oops/method.cpp6
-rw-r--r--src/share/vm/opto/callGenerator.cpp123
-rw-r--r--src/share/vm/opto/callGenerator.hpp3
-rw-r--r--src/share/vm/opto/doCall.cpp12
-rw-r--r--src/share/vm/opto/escape.cpp14
-rw-r--r--src/share/vm/opto/library_call.cpp369
-rw-r--r--src/share/vm/opto/runtime.cpp42
-rw-r--r--src/share/vm/opto/runtime.hpp3
-rw-r--r--src/share/vm/runtime/globals.hpp6
-rw-r--r--src/share/vm/runtime/stubRoutines.cpp4
-rw-r--r--src/share/vm/runtime/stubRoutines.hpp10
12 files changed, 599 insertions, 9 deletions
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
index 06fdb35be..2febc7b56 100644
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
@@ -110,6 +110,7 @@
template(sun_jkernel_DownloadManager, "sun/jkernel/DownloadManager") \
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \
+ template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \
\
/* Java runtime version access */ \
template(sun_misc_Version, "sun/misc/Version") \
@@ -723,6 +724,21 @@
/* java/lang/ref/Reference */ \
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
\
+ /* support for com.sum.crypto.provider.AESCrypt and some of its callers */ \
+ do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AESCrypt") \
+ do_intrinsic(_aescrypt_encryptBlock, com_sun_crypto_provider_aescrypt, encryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \
+ do_intrinsic(_aescrypt_decryptBlock, com_sun_crypto_provider_aescrypt, decryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \
+ do_name( encryptBlock_name, "encryptBlock") \
+ do_name( decryptBlock_name, "decryptBlock") \
+ do_signature(byteArray_int_byteArray_int_signature, "([BI[BI)V") \
+ \
+ do_class(com_sun_crypto_provider_cipherBlockChaining, "com/sun/crypto/provider/CipherBlockChaining") \
+ do_intrinsic(_cipherBlockChaining_encryptAESCrypt, com_sun_crypto_provider_cipherBlockChaining, encrypt_name, byteArray_int_int_byteArray_int_signature, F_R) \
+ do_intrinsic(_cipherBlockChaining_decryptAESCrypt, com_sun_crypto_provider_cipherBlockChaining, decrypt_name, byteArray_int_int_byteArray_int_signature, F_R) \
+ do_name( encrypt_name, "encrypt") \
+ do_name( decrypt_name, "decrypt") \
+ do_signature(byteArray_int_int_byteArray_int_signature, "([BII[BI)V") \
+ \
/* support for sun.misc.Unsafe */ \
do_class(sun_misc_Unsafe, "sun/misc/Unsafe") \
\
diff --git a/src/share/vm/oops/method.cpp b/src/share/vm/oops/method.cpp
index 5a1032f77..9849829ea 100644
--- a/src/share/vm/oops/method.cpp
+++ b/src/share/vm/oops/method.cpp
@@ -1155,8 +1155,12 @@ methodHandle Method::clone_with_new_data(methodHandle m, u_char* new_code, int n
vmSymbols::SID Method::klass_id_for_intrinsics(Klass* holder) {
// if loader is not the default loader (i.e., != NULL), we can't know the intrinsics
// because we are not loading from core libraries
- if (InstanceKlass::cast(holder)->class_loader() != NULL)
+ // exception: the AES intrinsics come from lib/ext/sunjce_provider.jar
+ // which does not use the class default class loader so we check for its loader here
+ if ((InstanceKlass::cast(holder)->class_loader() != NULL) &&
+ InstanceKlass::cast(holder)->class_loader()->klass()->name() != vmSymbols::sun_misc_Launcher_ExtClassLoader()) {
return vmSymbols::NO_SID; // regardless of name, no intrinsics here
+ }
// see if the klass name is well-known:
Symbol* klass_name = InstanceKlass::cast(holder)->name();
diff --git a/src/share/vm/opto/callGenerator.cpp b/src/share/vm/opto/callGenerator.cpp
index 547096b3d..93f2b859b 100644
--- a/src/share/vm/opto/callGenerator.cpp
+++ b/src/share/vm/opto/callGenerator.cpp
@@ -670,6 +670,129 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
}
+//------------------------PredictedIntrinsicGenerator------------------------------
+// Internal class which handles all predicted Intrinsic calls.
+class PredictedIntrinsicGenerator : public CallGenerator {
+ CallGenerator* _intrinsic;
+ CallGenerator* _cg;
+
+public:
+ PredictedIntrinsicGenerator(CallGenerator* intrinsic,
+ CallGenerator* cg)
+ : CallGenerator(cg->method())
+ {
+ _intrinsic = intrinsic;
+ _cg = cg;
+ }
+
+ virtual bool is_virtual() const { return true; }
+ virtual bool is_inlined() const { return true; }
+ virtual bool is_intrinsic() const { return true; }
+
+ virtual JVMState* generate(JVMState* jvms);
+};
+
+
+CallGenerator* CallGenerator::for_predicted_intrinsic(CallGenerator* intrinsic,
+ CallGenerator* cg) {
+ return new PredictedIntrinsicGenerator(intrinsic, cg);
+}
+
+
+JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms) {
+ GraphKit kit(jvms);
+ PhaseGVN& gvn = kit.gvn();
+
+ CompileLog* log = kit.C->log();
+ if (log != NULL) {
+ log->elem("predicted_intrinsic bci='%d' method='%d'",
+ jvms->bci(), log->identify(method()));
+ }
+
+ Node* slow_ctl = _intrinsic->generate_predicate(kit.sync_jvms());
+ if (kit.failing())
+ return NULL; // might happen because of NodeCountInliningCutoff
+
+ SafePointNode* slow_map = NULL;
+ JVMState* slow_jvms;
+ if (slow_ctl != NULL) {
+ PreserveJVMState pjvms(&kit);
+ kit.set_control(slow_ctl);
+ if (!kit.stopped()) {
+ slow_jvms = _cg->generate(kit.sync_jvms());
+ if (kit.failing())
+ return NULL; // might happen because of NodeCountInliningCutoff
+ assert(slow_jvms != NULL, "must be");
+ kit.add_exception_states_from(slow_jvms);
+ kit.set_map(slow_jvms->map());
+ if (!kit.stopped())
+ slow_map = kit.stop();
+ }
+ }
+
+ if (kit.stopped()) {
+ // Predicate is always false.
+ kit.set_jvms(slow_jvms);
+ return kit.transfer_exceptions_into_jvms();
+ }
+
+ // Generate intrinsic code:
+ JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms());
+ if (new_jvms == NULL) {
+ // Intrinsic failed, so use slow code or make a direct call.
+ if (slow_map == NULL) {
+ CallGenerator* cg = CallGenerator::for_direct_call(method());
+ new_jvms = cg->generate(kit.sync_jvms());
+ } else {
+ kit.set_jvms(slow_jvms);
+ return kit.transfer_exceptions_into_jvms();
+ }
+ }
+ kit.add_exception_states_from(new_jvms);
+ kit.set_jvms(new_jvms);
+
+ // Need to merge slow and fast?
+ if (slow_map == NULL) {
+ // The fast path is the only path remaining.
+ return kit.transfer_exceptions_into_jvms();
+ }
+
+ if (kit.stopped()) {
+ // Intrinsic method threw an exception, so it's just the slow path after all.
+ kit.set_jvms(slow_jvms);
+ return kit.transfer_exceptions_into_jvms();
+ }
+
+ // Finish the diamond.
+ kit.C->set_has_split_ifs(true); // Has chance for split-if optimization
+ RegionNode* region = new (kit.C) RegionNode(3);
+ region->init_req(1, kit.control());
+ region->init_req(2, slow_map->control());
+ kit.set_control(gvn.transform(region));
+ Node* iophi = PhiNode::make(region, kit.i_o(), Type::ABIO);
+ iophi->set_req(2, slow_map->i_o());
+ kit.set_i_o(gvn.transform(iophi));
+ kit.merge_memory(slow_map->merged_memory(), region, 2);
+ uint tos = kit.jvms()->stkoff() + kit.sp();
+ uint limit = slow_map->req();
+ for (uint i = TypeFunc::Parms; i < limit; i++) {
+ // Skip unused stack slots; fast forward to monoff();
+ if (i == tos) {
+ i = kit.jvms()->monoff();
+ if( i >= limit ) break;
+ }
+ Node* m = kit.map()->in(i);
+ Node* n = slow_map->in(i);
+ if (m != n) {
+ const Type* t = gvn.type(m)->meet(gvn.type(n));
+ Node* phi = PhiNode::make(region, m, t);
+ phi->set_req(2, n);
+ kit.map()->set_req(i, gvn.transform(phi));
+ }
+ }
+ return kit.transfer_exceptions_into_jvms();
+}
+
//-------------------------UncommonTrapCallGenerator-----------------------------
// Internal class which handles all out-of-line calls checking receiver type.
class UncommonTrapCallGenerator : public CallGenerator {
diff --git a/src/share/vm/opto/callGenerator.hpp b/src/share/vm/opto/callGenerator.hpp
index 3cfd39df6..ae59173bf 100644
--- a/src/share/vm/opto/callGenerator.hpp
+++ b/src/share/vm/opto/callGenerator.hpp
@@ -143,6 +143,9 @@ class CallGenerator : public ResourceObj {
// Registry for intrinsics:
static CallGenerator* for_intrinsic(ciMethod* m);
static void register_intrinsic(ciMethod* m, CallGenerator* cg);
+ static CallGenerator* for_predicted_intrinsic(CallGenerator* intrinsic,
+ CallGenerator* cg);
+ virtual Node* generate_predicate(JVMState* jvms) { return NULL; };
static void print_inlining(ciMethod* callee, int inline_level, int bci, const char* msg) {
if (PrintInlining)
diff --git a/src/share/vm/opto/doCall.cpp b/src/share/vm/opto/doCall.cpp
index 30a01f34b..95d148841 100644
--- a/src/share/vm/opto/doCall.cpp
+++ b/src/share/vm/opto/doCall.cpp
@@ -107,7 +107,17 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
// intrinsics handle strict f.p. correctly.
if (allow_inline && allow_intrinsics) {
CallGenerator* cg = find_intrinsic(callee, call_is_virtual);
- if (cg != NULL) return cg;
+ if (cg != NULL) {
+ if (cg->is_predicted()) {
+ // Code without intrinsic but, hopefully, inlined.
+ CallGenerator* inline_cg = this->call_generator(callee,
+ vtable_index, call_is_virtual, jvms, allow_inline, prof_factor, false);
+ if (inline_cg != NULL) {
+ cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg);
+ }
+ }
+ return cg;
+ }
}
// Do method handle calls.
diff --git a/src/share/vm/opto/escape.cpp b/src/share/vm/opto/escape.cpp
index 9fd318050..2fd6ad1ce 100644
--- a/src/share/vm/opto/escape.cpp
+++ b/src/share/vm/opto/escape.cpp
@@ -893,12 +893,16 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
arg_has_oops && (i > TypeFunc::Parms);
#ifdef ASSERT
if (!(is_arraycopy ||
- call->as_CallLeaf()->_name != NULL &&
- (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
- strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
- ) {
+ (call->as_CallLeaf()->_name != NULL &&
+ (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "aescrypt_encryptBlock") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "aescrypt_decryptBlock") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_encryptAESCrypt") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_decryptAESCrypt") == 0)
+ ))) {
call->dump();
- assert(false, "EA: unexpected CallLeaf");
+ fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name));
}
#endif
// Always process arraycopy's destination object since
diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
index 4f24d88f1..6b90061ff 100644
--- a/src/share/vm/opto/library_call.cpp
+++ b/src/share/vm/opto/library_call.cpp
@@ -44,18 +44,22 @@ class LibraryIntrinsic : public InlineCallGenerator {
public:
private:
bool _is_virtual;
+ bool _is_predicted;
vmIntrinsics::ID _intrinsic_id;
public:
- LibraryIntrinsic(ciMethod* m, bool is_virtual, vmIntrinsics::ID id)
+ LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, vmIntrinsics::ID id)
: InlineCallGenerator(m),
_is_virtual(is_virtual),
+ _is_predicted(is_predicted),
_intrinsic_id(id)
{
}
virtual bool is_intrinsic() const { return true; }
virtual bool is_virtual() const { return _is_virtual; }
+ virtual bool is_predicted() const { return _is_predicted; }
virtual JVMState* generate(JVMState* jvms);
+ virtual Node* generate_predicate(JVMState* jvms);
vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; }
};
@@ -83,6 +87,7 @@ class LibraryCallKit : public GraphKit {
int arg_size() const { return callee()->arg_size(); }
bool try_to_inline();
+ Node* try_to_predicate();
// Helper functions to inline natives
void push_result(RegionNode* region, PhiNode* value);
@@ -148,6 +153,7 @@ class LibraryCallKit : public GraphKit {
CallJavaNode* generate_method_call_virtual(vmIntrinsics::ID method_id) {
return generate_method_call(method_id, true, false);
}
+ Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static);
Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2);
Node* make_string_method_node(int opcode, Node* str1, Node* str2);
@@ -253,6 +259,10 @@ class LibraryCallKit : public GraphKit {
bool inline_reverseBytes(vmIntrinsics::ID id);
bool inline_reference_get();
+ bool inline_aescrypt_Block(vmIntrinsics::ID id);
+ bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id);
+ Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting);
+ Node* get_key_start_from_aescrypt_object(Node* aescrypt_object);
};
@@ -306,6 +316,8 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
}
}
+ bool is_predicted = false;
+
switch (id) {
case vmIntrinsics::_compareTo:
if (!SpecialStringCompareTo) return NULL;
@@ -413,6 +425,18 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
break;
#endif
+ case vmIntrinsics::_aescrypt_encryptBlock:
+ case vmIntrinsics::_aescrypt_decryptBlock:
+ if (!UseAESIntrinsics) return NULL;
+ break;
+
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ if (!UseAESIntrinsics) return NULL;
+ // these two require the predicated logic
+ is_predicted = true;
+ break;
+
default:
assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility");
assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?");
@@ -444,7 +468,7 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
if (!InlineUnsafeOps) return NULL;
}
- return new LibraryIntrinsic(m, is_virtual, (vmIntrinsics::ID) id);
+ return new LibraryIntrinsic(m, is_virtual, is_predicted, (vmIntrinsics::ID) id);
}
//----------------------register_library_intrinsics-----------------------
@@ -496,6 +520,47 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) {
return NULL;
}
+Node* LibraryIntrinsic::generate_predicate(JVMState* jvms) {
+ LibraryCallKit kit(jvms, this);
+ Compile* C = kit.C;
+ int nodes = C->unique();
+#ifndef PRODUCT
+ assert(is_predicted(), "sanity");
+ if ((PrintIntrinsics || PrintInlining NOT_PRODUCT( || PrintOptoInlining) ) && Verbose) {
+ char buf[1000];
+ const char* str = vmIntrinsics::short_name_as_C_string(intrinsic_id(), buf, sizeof(buf));
+ tty->print_cr("Predicate for intrinsic %s", str);
+ }
+#endif
+
+ Node* slow_ctl = kit.try_to_predicate();
+ if (!kit.failing()) {
+ if (C->log()) {
+ C->log()->elem("predicate_intrinsic id='%s'%s nodes='%d'",
+ vmIntrinsics::name_at(intrinsic_id()),
+ (is_virtual() ? " virtual='1'" : ""),
+ C->unique() - nodes);
+ }
+ return slow_ctl; // Could be NULL if the check folds.
+ }
+
+ // The intrinsic bailed out
+ if (PrintIntrinsics || PrintInlining NOT_PRODUCT( || PrintOptoInlining) ) {
+ if (jvms->has_method()) {
+ // Not a root compile.
+ const char* msg = "failed to generate predicate for intrinsic";
+ CompileTask::print_inlining(kit.callee(), jvms->depth() - 1, kit.bci(), msg);
+ } else {
+ // Root compile
+ tty->print("Did not generate predicate for intrinsic %s%s at bci:%d in",
+ vmIntrinsics::name_at(intrinsic_id()),
+ (is_virtual() ? " (virtual)" : ""), kit.bci());
+ }
+ }
+ C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed);
+ return NULL;
+}
+
bool LibraryCallKit::try_to_inline() {
// Handle symbolic names for otherwise undistinguished boolean switches:
const bool is_store = true;
@@ -767,6 +832,14 @@ bool LibraryCallKit::try_to_inline() {
case vmIntrinsics::_Reference_get:
return inline_reference_get();
+ case vmIntrinsics::_aescrypt_encryptBlock:
+ case vmIntrinsics::_aescrypt_decryptBlock:
+ return inline_aescrypt_Block(intrinsic_id());
+
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ return inline_cipherBlockChaining_AESCrypt(intrinsic_id());
+
default:
// If you get here, it may be that someone has added a new intrinsic
// to the list in vmSymbols.hpp without implementing it here.
@@ -780,6 +853,36 @@ bool LibraryCallKit::try_to_inline() {
}
}
+Node* LibraryCallKit::try_to_predicate() {
+ if (!jvms()->has_method()) {
+ // Root JVMState has a null method.
+ assert(map()->memory()->Opcode() == Op_Parm, "");
+ // Insert the memory aliasing node
+ set_all_memory(reset_memory());
+ }
+ assert(merged_memory(), "");
+
+ switch (intrinsic_id()) {
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ return inline_cipherBlockChaining_AESCrypt_predicate(false);
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ return inline_cipherBlockChaining_AESCrypt_predicate(true);
+
+ default:
+ // If you get here, it may be that someone has added a new intrinsic
+ // to the list in vmSymbols.hpp without implementing it here.
+#ifndef PRODUCT
+ if ((PrintMiscellaneous && (Verbose || WizardMode)) || PrintOpto) {
+ tty->print_cr("*** Warning: Unimplemented predicate for intrinsic %s(%d)",
+ vmIntrinsics::name_at(intrinsic_id()), intrinsic_id());
+ }
+#endif
+ Node* slow_ctl = control();
+ set_control(top()); // No fast path instrinsic
+ return slow_ctl;
+ }
+}
+
//------------------------------push_result------------------------------
// Helper function for finishing intrinsics.
void LibraryCallKit::push_result(RegionNode* region, PhiNode* value) {
@@ -5613,3 +5716,265 @@ bool LibraryCallKit::inline_reference_get() {
push(result);
return true;
}
+
+
+Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString,
+ bool is_exact=true, bool is_static=false) {
+
+ const TypeInstPtr* tinst = _gvn.type(fromObj)->isa_instptr();
+ assert(tinst != NULL, "obj is null");
+ assert(tinst->klass()->is_loaded(), "obj is not loaded");
+ assert(!is_exact || tinst->klass_is_exact(), "klass not exact");
+
+ ciField* field = tinst->klass()->as_instance_klass()->get_field_by_name(ciSymbol::make(fieldName),
+ ciSymbol::make(fieldTypeString),
+ is_static);
+ if (field == NULL) return (Node *) NULL;
+ assert (field != NULL, "undefined field");
+
+ // Next code copied from Parse::do_get_xxx():
+
+ // Compute address and memory type.
+ int offset = field->offset_in_bytes();
+ bool is_vol = field->is_volatile();
+ ciType* field_klass = field->type();
+ assert(field_klass->is_loaded(), "should be loaded");
+ const TypePtr* adr_type = C->alias_type(field)->adr_type();
+ Node *adr = basic_plus_adr(fromObj, fromObj, offset);
+ BasicType bt = field->layout_type();
+
+ // Build the resultant type of the load
+ const Type *type = TypeOopPtr::make_from_klass(field_klass->as_klass());
+
+ // Build the load.
+ Node* loadedField = make_load(NULL, adr, type, bt, adr_type, is_vol);
+ return loadedField;
+}
+
+
+//------------------------------inline_aescrypt_Block-----------------------
+bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) {
+ address stubAddr;
+ const char *stubName;
+ assert(UseAES, "need AES instruction support");
+
+ switch(id) {
+ case vmIntrinsics::_aescrypt_encryptBlock:
+ stubAddr = StubRoutines::aescrypt_encryptBlock();
+ stubName = "aescrypt_encryptBlock";
+ break;
+ case vmIntrinsics::_aescrypt_decryptBlock:
+ stubAddr = StubRoutines::aescrypt_decryptBlock();
+ stubName = "aescrypt_decryptBlock";
+ break;
+ }
+ if (stubAddr == NULL) return false;
+
+ // Restore the stack and pop off the arguments.
+ int nargs = 5; // this + 2 oop/offset combos
+ assert(callee()->signature()->size() == nargs-1, "encryptBlock has 4 arguments");
+
+ Node *aescrypt_object = argument(0);
+ Node *src = argument(1);
+ Node *src_offset = argument(2);
+ Node *dest = argument(3);
+ Node *dest_offset = argument(4);
+
+ // (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");
+
+ // for the quick and dirty code we will skip all the checks.
+ // we are just trying to get the call to be generated.
+ 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);
+ }
+
+ // now need to get the start of its expanded key array
+ // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java
+ Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object);
+ if (k_start == NULL) return false;
+
+ // Call the stub.
+ make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::aescrypt_block_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ src_start, dest_start, k_start);
+
+ return true;
+}
+
+//------------------------------inline_cipherBlockChaining_AESCrypt-----------------------
+bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) {
+ address stubAddr;
+ const char *stubName;
+
+ assert(UseAES, "need AES instruction support");
+
+ switch(id) {
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ stubAddr = StubRoutines::cipherBlockChaining_encryptAESCrypt();
+ stubName = "cipherBlockChaining_encryptAESCrypt";
+ break;
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ stubAddr = StubRoutines::cipherBlockChaining_decryptAESCrypt();
+ stubName = "cipherBlockChaining_decryptAESCrypt";
+ break;
+ }
+ if (stubAddr == NULL) return false;
+
+
+ // Restore the stack and pop off the arguments.
+ int nargs = 6; // this + oop/offset + len + oop/offset
+ assert(callee()->signature()->size() == nargs-1, "wrong number of arguments");
+ Node *cipherBlockChaining_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(cipherBlockChaining_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(cipherBlockChaining_object)->isa_instptr();
+ assert(tinst != NULL, "CBC obj is null");
+ assert(tinst->klass()->is_loaded(), "CBC obj is not loaded");
+ ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt"));
+ if (!klass_AESCrypt->is_loaded()) return false;
+
+ 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(C) 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;
+
+ // similarly, get the start address of the r vector
+ Node* objRvec = load_field_from_object(cipherBlockChaining_object, "r", "[B", /*is_exact*/ false);
+ if (objRvec == NULL) return false;
+ Node* r_start = array_element_address(objRvec, intcon(0), T_BYTE);
+
+ // Call the stub, passing src_start, dest_start, k_start, r_start and src_len
+ make_runtime_call(RC_LEAF|RC_NO_FP,
+ OptoRuntime::cipherBlockChaining_aescrypt_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ src_start, dest_start, k_start, r_start, len);
+
+ // return is void so no result needs to be pushed
+
+ return true;
+}
+
+//------------------------------get_key_start_from_aescrypt_object-----------------------
+Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) {
+ Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I", /*is_exact*/ false);
+ assert (objAESCryptKey != NULL, "wrong version of com.sun.crypto.provider.AESCrypt");
+ if (objAESCryptKey == NULL) return (Node *) NULL;
+
+ // now have the array, need to get the start address of the K array
+ Node* k_start = array_element_address(objAESCryptKey, intcon(0), T_INT);
+ return k_start;
+}
+
+//----------------------------inline_cipherBlockChaining_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_cipherBlockChaining_AESCrypt_predicate(bool decrypting) {
+ // First, check receiver for NULL since it is virtual method.
+ int nargs = arg_size();
+ Node* objCBC = argument(0);
+ _sp += nargs;
+ objCBC = do_null_check(objCBC, T_OBJECT);
+ _sp -= nargs;
+
+ if (stopped()) return NULL; // Always NULL
+
+ // Load embeddedCipher field of CipherBlockChaining object.
+ Node* embeddedCipherObj = load_field_from_object(objCBC, "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 CipherBlockChaining object
+ const TypeInstPtr* tinst = _gvn.type(objCBC)->isa_instptr();
+ assert(tinst != NULL, "CBCobj is null");
+ assert(tinst->klass()->is_loaded(), "CBCobj 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();
+
+ _sp += nargs; // gen_instanceof might do an uncommon trap
+ Node* instof = gen_instanceof(embeddedCipherObj, makecon(TypeKlassPtr::make(instklass_AESCrypt)));
+ _sp -= nargs;
+ Node* cmp_instof = _gvn.transform(new (C) CmpINode(instof, intcon(1)));
+ Node* bool_instof = _gvn.transform(new (C) 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(C) RegionNode(3);
+ region->init_req(1, instof_false);
+ Node* src = argument(1);
+ Node *dest = argument(4);
+ Node* cmp_src_dest = _gvn.transform(new (C) CmpPNode(src, dest));
+ Node* bool_src_dest = _gvn.transform(new (C) 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);
+
+}
+
+
diff --git a/src/share/vm/opto/runtime.cpp b/src/share/vm/opto/runtime.cpp
index bb050533d..51987e25e 100644
--- a/src/share/vm/opto/runtime.cpp
+++ b/src/share/vm/opto/runtime.cpp
@@ -811,6 +811,48 @@ const TypeFunc* OptoRuntime::array_fill_Type() {
return TypeFunc::make(domain, range);
}
+// for aescrypt encrypt/decrypt operations, just three pointers returning void (length is constant)
+const TypeFunc* OptoRuntime::aescrypt_block_Type() {
+ // create input type (domain)
+ int num_args = 3;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // src
+ fields[argp++] = TypePtr::NOTNULL; // dest
+ fields[argp++] = TypePtr::NOTNULL; // k array
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // no result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = NULL; // void
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
+ return TypeFunc::make(domain, range);
+}
+
+// for cipherBlockChaining calls of aescrypt encrypt/decrypt, four pointers and a length, returning void
+const TypeFunc* OptoRuntime::cipherBlockChaining_aescrypt_Type() {
+ // create input type (domain)
+ int num_args = 5;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // src
+ fields[argp++] = TypePtr::NOTNULL; // dest
+ fields[argp++] = TypePtr::NOTNULL; // k array
+ fields[argp++] = TypePtr::NOTNULL; // r array
+ fields[argp++] = TypeInt::INT; // src len
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // no result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = NULL; // void
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
+ return TypeFunc::make(domain, range);
+}
+
//------------- Interpreter state access for on stack replacement
const TypeFunc* OptoRuntime::osr_end_Type() {
// create input type (domain)
diff --git a/src/share/vm/opto/runtime.hpp b/src/share/vm/opto/runtime.hpp
index c70777267..13da255b7 100644
--- a/src/share/vm/opto/runtime.hpp
+++ b/src/share/vm/opto/runtime.hpp
@@ -280,6 +280,9 @@ private:
static const TypeFunc* array_fill_Type();
+ static const TypeFunc* aescrypt_block_Type();
+ static const TypeFunc* cipherBlockChaining_aescrypt_Type();
+
// leaf on stack replacement interpreter accessor types
static const TypeFunc* osr_end_Type();
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
index e073cbcd0..42c3cdf6d 100644
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -533,6 +533,9 @@ class CommandLineFlags {
product(intx, UseSSE, 99, \
"Highest supported SSE instructions set on x86/x64") \
\
+ product(bool, UseAES, false, \
+ "Control whether AES instructions can be used on x86/x64") \
+ \
product(uintx, LargePageSizeInBytes, 0, \
"Large page size (0 to let VM choose the page size") \
\
@@ -635,6 +638,9 @@ class CommandLineFlags {
product(bool, UseSSE42Intrinsics, false, \
"SSE4.2 versions of intrinsics") \
\
+ product(bool, UseAESIntrinsics, false, \
+ "use intrinsics for AES versions of crypto") \
+ \
develop(bool, TraceCallFixup, false, \
"traces all call fixups") \
\
diff --git a/src/share/vm/runtime/stubRoutines.cpp b/src/share/vm/runtime/stubRoutines.cpp
index 5ca4ba599..98d428abd 100644
--- a/src/share/vm/runtime/stubRoutines.cpp
+++ b/src/share/vm/runtime/stubRoutines.cpp
@@ -120,6 +120,10 @@ address StubRoutines::_arrayof_jbyte_fill;
address StubRoutines::_arrayof_jshort_fill;
address StubRoutines::_arrayof_jint_fill;
+address StubRoutines::_aescrypt_encryptBlock = NULL;
+address StubRoutines::_aescrypt_decryptBlock = NULL;
+address StubRoutines::_cipherBlockChaining_encryptAESCrypt = NULL;
+address StubRoutines::_cipherBlockChaining_decryptAESCrypt = NULL;
double (* StubRoutines::_intrinsic_log )(double) = NULL;
double (* StubRoutines::_intrinsic_log10 )(double) = NULL;
diff --git a/src/share/vm/runtime/stubRoutines.hpp b/src/share/vm/runtime/stubRoutines.hpp
index 0e583aea0..91f273e65 100644
--- a/src/share/vm/runtime/stubRoutines.hpp
+++ b/src/share/vm/runtime/stubRoutines.hpp
@@ -199,6 +199,11 @@ class StubRoutines: AllStatic {
// zero heap space aligned to jlong (8 bytes)
static address _zero_aligned_words;
+ static address _aescrypt_encryptBlock;
+ static address _aescrypt_decryptBlock;
+ static address _cipherBlockChaining_encryptAESCrypt;
+ static address _cipherBlockChaining_decryptAESCrypt;
+
// These are versions of the java.lang.Math methods which perform
// the same operations as the intrinsic version. They are used for
// constant folding in the compiler to ensure equivalence. If the
@@ -330,6 +335,11 @@ class StubRoutines: AllStatic {
static address arrayof_jshort_fill() { return _arrayof_jshort_fill; }
static address arrayof_jint_fill() { return _arrayof_jint_fill; }
+ static address aescrypt_encryptBlock() { return _aescrypt_encryptBlock; }
+ static address aescrypt_decryptBlock() { return _aescrypt_decryptBlock; }
+ static address cipherBlockChaining_encryptAESCrypt() { return _cipherBlockChaining_encryptAESCrypt; }
+ static address cipherBlockChaining_decryptAESCrypt() { return _cipherBlockChaining_decryptAESCrypt; }
+
static address select_fill_function(BasicType t, bool aligned, const char* &name);
static address zero_aligned_words() { return _zero_aligned_words; }