Mercurial > hg > graal-compiler
comparison src/share/vm/opto/library_call.cpp @ 6894:a3ecd773a7b9
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
author | kvn |
---|---|
date | Wed, 24 Oct 2012 14:33:22 -0700 |
parents | cfe522e6461c |
children | beebba0acc11 |
comparison
equal
deleted
inserted
replaced
6893:b2c669fd8114 | 6894:a3ecd773a7b9 |
---|---|
42 class LibraryIntrinsic : public InlineCallGenerator { | 42 class LibraryIntrinsic : public InlineCallGenerator { |
43 // Extend the set of intrinsics known to the runtime: | 43 // Extend the set of intrinsics known to the runtime: |
44 public: | 44 public: |
45 private: | 45 private: |
46 bool _is_virtual; | 46 bool _is_virtual; |
47 bool _is_predicted; | |
47 vmIntrinsics::ID _intrinsic_id; | 48 vmIntrinsics::ID _intrinsic_id; |
48 | 49 |
49 public: | 50 public: |
50 LibraryIntrinsic(ciMethod* m, bool is_virtual, vmIntrinsics::ID id) | 51 LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, vmIntrinsics::ID id) |
51 : InlineCallGenerator(m), | 52 : InlineCallGenerator(m), |
52 _is_virtual(is_virtual), | 53 _is_virtual(is_virtual), |
54 _is_predicted(is_predicted), | |
53 _intrinsic_id(id) | 55 _intrinsic_id(id) |
54 { | 56 { |
55 } | 57 } |
56 virtual bool is_intrinsic() const { return true; } | 58 virtual bool is_intrinsic() const { return true; } |
57 virtual bool is_virtual() const { return _is_virtual; } | 59 virtual bool is_virtual() const { return _is_virtual; } |
60 virtual bool is_predicted() const { return _is_predicted; } | |
58 virtual JVMState* generate(JVMState* jvms); | 61 virtual JVMState* generate(JVMState* jvms); |
62 virtual Node* generate_predicate(JVMState* jvms); | |
59 vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; } | 63 vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; } |
60 }; | 64 }; |
61 | 65 |
62 | 66 |
63 // Local helper class for LibraryIntrinsic: | 67 // Local helper class for LibraryIntrinsic: |
81 ciMethod* callee() const { return _intrinsic->method(); } | 85 ciMethod* callee() const { return _intrinsic->method(); } |
82 ciSignature* signature() const { return callee()->signature(); } | 86 ciSignature* signature() const { return callee()->signature(); } |
83 int arg_size() const { return callee()->arg_size(); } | 87 int arg_size() const { return callee()->arg_size(); } |
84 | 88 |
85 bool try_to_inline(); | 89 bool try_to_inline(); |
90 Node* try_to_predicate(); | |
86 | 91 |
87 // Helper functions to inline natives | 92 // Helper functions to inline natives |
88 void push_result(RegionNode* region, PhiNode* value); | 93 void push_result(RegionNode* region, PhiNode* value); |
89 Node* generate_guard(Node* test, RegionNode* region, float true_prob); | 94 Node* generate_guard(Node* test, RegionNode* region, float true_prob); |
90 Node* generate_slow_guard(Node* test, RegionNode* region); | 95 Node* generate_slow_guard(Node* test, RegionNode* region); |
146 return generate_method_call(method_id, false, true); | 151 return generate_method_call(method_id, false, true); |
147 } | 152 } |
148 CallJavaNode* generate_method_call_virtual(vmIntrinsics::ID method_id) { | 153 CallJavaNode* generate_method_call_virtual(vmIntrinsics::ID method_id) { |
149 return generate_method_call(method_id, true, false); | 154 return generate_method_call(method_id, true, false); |
150 } | 155 } |
156 Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static); | |
151 | 157 |
152 Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2); | 158 Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2); |
153 Node* make_string_method_node(int opcode, Node* str1, Node* str2); | 159 Node* make_string_method_node(int opcode, Node* str1, Node* str2); |
154 bool inline_string_compareTo(); | 160 bool inline_string_compareTo(); |
155 bool inline_string_indexOf(); | 161 bool inline_string_indexOf(); |
251 bool inline_numberOfTrailingZeros(vmIntrinsics::ID id); | 257 bool inline_numberOfTrailingZeros(vmIntrinsics::ID id); |
252 bool inline_bitCount(vmIntrinsics::ID id); | 258 bool inline_bitCount(vmIntrinsics::ID id); |
253 bool inline_reverseBytes(vmIntrinsics::ID id); | 259 bool inline_reverseBytes(vmIntrinsics::ID id); |
254 | 260 |
255 bool inline_reference_get(); | 261 bool inline_reference_get(); |
262 bool inline_aescrypt_Block(vmIntrinsics::ID id); | |
263 bool inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id); | |
264 Node* inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting); | |
265 Node* get_key_start_from_aescrypt_object(Node* aescrypt_object); | |
256 }; | 266 }; |
257 | 267 |
258 | 268 |
259 //---------------------------make_vm_intrinsic---------------------------- | 269 //---------------------------make_vm_intrinsic---------------------------- |
260 CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { | 270 CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { |
304 default: | 314 default: |
305 return NULL; | 315 return NULL; |
306 } | 316 } |
307 } | 317 } |
308 | 318 |
319 bool is_predicted = false; | |
320 | |
309 switch (id) { | 321 switch (id) { |
310 case vmIntrinsics::_compareTo: | 322 case vmIntrinsics::_compareTo: |
311 if (!SpecialStringCompareTo) return NULL; | 323 if (!SpecialStringCompareTo) return NULL; |
312 break; | 324 break; |
313 case vmIntrinsics::_indexOf: | 325 case vmIntrinsics::_indexOf: |
411 #else | 423 #else |
412 if (!Matcher::match_rule_supported(Op_GetAndSetP)) return NULL; | 424 if (!Matcher::match_rule_supported(Op_GetAndSetP)) return NULL; |
413 break; | 425 break; |
414 #endif | 426 #endif |
415 | 427 |
428 case vmIntrinsics::_aescrypt_encryptBlock: | |
429 case vmIntrinsics::_aescrypt_decryptBlock: | |
430 if (!UseAESIntrinsics) return NULL; | |
431 break; | |
432 | |
433 case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: | |
434 case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: | |
435 if (!UseAESIntrinsics) return NULL; | |
436 // these two require the predicated logic | |
437 is_predicted = true; | |
438 break; | |
439 | |
416 default: | 440 default: |
417 assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); | 441 assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility"); |
418 assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); | 442 assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?"); |
419 break; | 443 break; |
420 } | 444 } |
442 // -XX:-InlineUnsafeOps disables natives from the Unsafe class. | 466 // -XX:-InlineUnsafeOps disables natives from the Unsafe class. |
443 if (m->holder()->name() == ciSymbol::sun_misc_Unsafe()) { | 467 if (m->holder()->name() == ciSymbol::sun_misc_Unsafe()) { |
444 if (!InlineUnsafeOps) return NULL; | 468 if (!InlineUnsafeOps) return NULL; |
445 } | 469 } |
446 | 470 |
447 return new LibraryIntrinsic(m, is_virtual, (vmIntrinsics::ID) id); | 471 return new LibraryIntrinsic(m, is_virtual, is_predicted, (vmIntrinsics::ID) id); |
448 } | 472 } |
449 | 473 |
450 //----------------------register_library_intrinsics----------------------- | 474 //----------------------register_library_intrinsics----------------------- |
451 // Initialize this file's data structures, for each Compile instance. | 475 // Initialize this file's data structures, for each Compile instance. |
452 void Compile::register_library_intrinsics() { | 476 void Compile::register_library_intrinsics() { |
486 const char* msg = is_virtual() ? "failed to inline (intrinsic, virtual)" : "failed to inline (intrinsic)"; | 510 const char* msg = is_virtual() ? "failed to inline (intrinsic, virtual)" : "failed to inline (intrinsic)"; |
487 CompileTask::print_inlining(kit.callee(), jvms->depth() - 1, kit.bci(), msg); | 511 CompileTask::print_inlining(kit.callee(), jvms->depth() - 1, kit.bci(), msg); |
488 } else { | 512 } else { |
489 // Root compile | 513 // Root compile |
490 tty->print("Did not generate intrinsic %s%s at bci:%d in", | 514 tty->print("Did not generate intrinsic %s%s at bci:%d in", |
515 vmIntrinsics::name_at(intrinsic_id()), | |
516 (is_virtual() ? " (virtual)" : ""), kit.bci()); | |
517 } | |
518 } | |
519 C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed); | |
520 return NULL; | |
521 } | |
522 | |
523 Node* LibraryIntrinsic::generate_predicate(JVMState* jvms) { | |
524 LibraryCallKit kit(jvms, this); | |
525 Compile* C = kit.C; | |
526 int nodes = C->unique(); | |
527 #ifndef PRODUCT | |
528 assert(is_predicted(), "sanity"); | |
529 if ((PrintIntrinsics || PrintInlining NOT_PRODUCT( || PrintOptoInlining) ) && Verbose) { | |
530 char buf[1000]; | |
531 const char* str = vmIntrinsics::short_name_as_C_string(intrinsic_id(), buf, sizeof(buf)); | |
532 tty->print_cr("Predicate for intrinsic %s", str); | |
533 } | |
534 #endif | |
535 | |
536 Node* slow_ctl = kit.try_to_predicate(); | |
537 if (!kit.failing()) { | |
538 if (C->log()) { | |
539 C->log()->elem("predicate_intrinsic id='%s'%s nodes='%d'", | |
540 vmIntrinsics::name_at(intrinsic_id()), | |
541 (is_virtual() ? " virtual='1'" : ""), | |
542 C->unique() - nodes); | |
543 } | |
544 return slow_ctl; // Could be NULL if the check folds. | |
545 } | |
546 | |
547 // The intrinsic bailed out | |
548 if (PrintIntrinsics || PrintInlining NOT_PRODUCT( || PrintOptoInlining) ) { | |
549 if (jvms->has_method()) { | |
550 // Not a root compile. | |
551 const char* msg = "failed to generate predicate for intrinsic"; | |
552 CompileTask::print_inlining(kit.callee(), jvms->depth() - 1, kit.bci(), msg); | |
553 } else { | |
554 // Root compile | |
555 tty->print("Did not generate predicate for intrinsic %s%s at bci:%d in", | |
491 vmIntrinsics::name_at(intrinsic_id()), | 556 vmIntrinsics::name_at(intrinsic_id()), |
492 (is_virtual() ? " (virtual)" : ""), kit.bci()); | 557 (is_virtual() ? " (virtual)" : ""), kit.bci()); |
493 } | 558 } |
494 } | 559 } |
495 C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed); | 560 C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed); |
765 return inline_native_Reflection_getCallerClass(); | 830 return inline_native_Reflection_getCallerClass(); |
766 | 831 |
767 case vmIntrinsics::_Reference_get: | 832 case vmIntrinsics::_Reference_get: |
768 return inline_reference_get(); | 833 return inline_reference_get(); |
769 | 834 |
835 case vmIntrinsics::_aescrypt_encryptBlock: | |
836 case vmIntrinsics::_aescrypt_decryptBlock: | |
837 return inline_aescrypt_Block(intrinsic_id()); | |
838 | |
839 case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: | |
840 case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: | |
841 return inline_cipherBlockChaining_AESCrypt(intrinsic_id()); | |
842 | |
770 default: | 843 default: |
771 // If you get here, it may be that someone has added a new intrinsic | 844 // If you get here, it may be that someone has added a new intrinsic |
772 // to the list in vmSymbols.hpp without implementing it here. | 845 // to the list in vmSymbols.hpp without implementing it here. |
773 #ifndef PRODUCT | 846 #ifndef PRODUCT |
774 if ((PrintMiscellaneous && (Verbose || WizardMode)) || PrintOpto) { | 847 if ((PrintMiscellaneous && (Verbose || WizardMode)) || PrintOpto) { |
775 tty->print_cr("*** Warning: Unimplemented intrinsic %s(%d)", | 848 tty->print_cr("*** Warning: Unimplemented intrinsic %s(%d)", |
776 vmIntrinsics::name_at(intrinsic_id()), intrinsic_id()); | 849 vmIntrinsics::name_at(intrinsic_id()), intrinsic_id()); |
777 } | 850 } |
778 #endif | 851 #endif |
779 return false; | 852 return false; |
853 } | |
854 } | |
855 | |
856 Node* LibraryCallKit::try_to_predicate() { | |
857 if (!jvms()->has_method()) { | |
858 // Root JVMState has a null method. | |
859 assert(map()->memory()->Opcode() == Op_Parm, ""); | |
860 // Insert the memory aliasing node | |
861 set_all_memory(reset_memory()); | |
862 } | |
863 assert(merged_memory(), ""); | |
864 | |
865 switch (intrinsic_id()) { | |
866 case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: | |
867 return inline_cipherBlockChaining_AESCrypt_predicate(false); | |
868 case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: | |
869 return inline_cipherBlockChaining_AESCrypt_predicate(true); | |
870 | |
871 default: | |
872 // If you get here, it may be that someone has added a new intrinsic | |
873 // to the list in vmSymbols.hpp without implementing it here. | |
874 #ifndef PRODUCT | |
875 if ((PrintMiscellaneous && (Verbose || WizardMode)) || PrintOpto) { | |
876 tty->print_cr("*** Warning: Unimplemented predicate for intrinsic %s(%d)", | |
877 vmIntrinsics::name_at(intrinsic_id()), intrinsic_id()); | |
878 } | |
879 #endif | |
880 Node* slow_ctl = control(); | |
881 set_control(top()); // No fast path instrinsic | |
882 return slow_ctl; | |
780 } | 883 } |
781 } | 884 } |
782 | 885 |
783 //------------------------------push_result------------------------------ | 886 //------------------------------push_result------------------------------ |
784 // Helper function for finishing intrinsics. | 887 // Helper function for finishing intrinsics. |
5611 insert_mem_bar(Op_MemBarCPUOrder); | 5714 insert_mem_bar(Op_MemBarCPUOrder); |
5612 | 5715 |
5613 push(result); | 5716 push(result); |
5614 return true; | 5717 return true; |
5615 } | 5718 } |
5719 | |
5720 | |
5721 Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, | |
5722 bool is_exact=true, bool is_static=false) { | |
5723 | |
5724 const TypeInstPtr* tinst = _gvn.type(fromObj)->isa_instptr(); | |
5725 assert(tinst != NULL, "obj is null"); | |
5726 assert(tinst->klass()->is_loaded(), "obj is not loaded"); | |
5727 assert(!is_exact || tinst->klass_is_exact(), "klass not exact"); | |
5728 | |
5729 ciField* field = tinst->klass()->as_instance_klass()->get_field_by_name(ciSymbol::make(fieldName), | |
5730 ciSymbol::make(fieldTypeString), | |
5731 is_static); | |
5732 if (field == NULL) return (Node *) NULL; | |
5733 assert (field != NULL, "undefined field"); | |
5734 | |
5735 // Next code copied from Parse::do_get_xxx(): | |
5736 | |
5737 // Compute address and memory type. | |
5738 int offset = field->offset_in_bytes(); | |
5739 bool is_vol = field->is_volatile(); | |
5740 ciType* field_klass = field->type(); | |
5741 assert(field_klass->is_loaded(), "should be loaded"); | |
5742 const TypePtr* adr_type = C->alias_type(field)->adr_type(); | |
5743 Node *adr = basic_plus_adr(fromObj, fromObj, offset); | |
5744 BasicType bt = field->layout_type(); | |
5745 | |
5746 // Build the resultant type of the load | |
5747 const Type *type = TypeOopPtr::make_from_klass(field_klass->as_klass()); | |
5748 | |
5749 // Build the load. | |
5750 Node* loadedField = make_load(NULL, adr, type, bt, adr_type, is_vol); | |
5751 return loadedField; | |
5752 } | |
5753 | |
5754 | |
5755 //------------------------------inline_aescrypt_Block----------------------- | |
5756 bool LibraryCallKit::inline_aescrypt_Block(vmIntrinsics::ID id) { | |
5757 address stubAddr; | |
5758 const char *stubName; | |
5759 assert(UseAES, "need AES instruction support"); | |
5760 | |
5761 switch(id) { | |
5762 case vmIntrinsics::_aescrypt_encryptBlock: | |
5763 stubAddr = StubRoutines::aescrypt_encryptBlock(); | |
5764 stubName = "aescrypt_encryptBlock"; | |
5765 break; | |
5766 case vmIntrinsics::_aescrypt_decryptBlock: | |
5767 stubAddr = StubRoutines::aescrypt_decryptBlock(); | |
5768 stubName = "aescrypt_decryptBlock"; | |
5769 break; | |
5770 } | |
5771 if (stubAddr == NULL) return false; | |
5772 | |
5773 // Restore the stack and pop off the arguments. | |
5774 int nargs = 5; // this + 2 oop/offset combos | |
5775 assert(callee()->signature()->size() == nargs-1, "encryptBlock has 4 arguments"); | |
5776 | |
5777 Node *aescrypt_object = argument(0); | |
5778 Node *src = argument(1); | |
5779 Node *src_offset = argument(2); | |
5780 Node *dest = argument(3); | |
5781 Node *dest_offset = argument(4); | |
5782 | |
5783 // (1) src and dest are arrays. | |
5784 const Type* src_type = src->Value(&_gvn); | |
5785 const Type* dest_type = dest->Value(&_gvn); | |
5786 const TypeAryPtr* top_src = src_type->isa_aryptr(); | |
5787 const TypeAryPtr* top_dest = dest_type->isa_aryptr(); | |
5788 assert (top_src != NULL && top_src->klass() != NULL && top_dest != NULL && top_dest->klass() != NULL, "args are strange"); | |
5789 | |
5790 // for the quick and dirty code we will skip all the checks. | |
5791 // we are just trying to get the call to be generated. | |
5792 Node* src_start = src; | |
5793 Node* dest_start = dest; | |
5794 if (src_offset != NULL || dest_offset != NULL) { | |
5795 assert(src_offset != NULL && dest_offset != NULL, ""); | |
5796 src_start = array_element_address(src, src_offset, T_BYTE); | |
5797 dest_start = array_element_address(dest, dest_offset, T_BYTE); | |
5798 } | |
5799 | |
5800 // now need to get the start of its expanded key array | |
5801 // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java | |
5802 Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); | |
5803 if (k_start == NULL) return false; | |
5804 | |
5805 // Call the stub. | |
5806 make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::aescrypt_block_Type(), | |
5807 stubAddr, stubName, TypePtr::BOTTOM, | |
5808 src_start, dest_start, k_start); | |
5809 | |
5810 return true; | |
5811 } | |
5812 | |
5813 //------------------------------inline_cipherBlockChaining_AESCrypt----------------------- | |
5814 bool LibraryCallKit::inline_cipherBlockChaining_AESCrypt(vmIntrinsics::ID id) { | |
5815 address stubAddr; | |
5816 const char *stubName; | |
5817 | |
5818 assert(UseAES, "need AES instruction support"); | |
5819 | |
5820 switch(id) { | |
5821 case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: | |
5822 stubAddr = StubRoutines::cipherBlockChaining_encryptAESCrypt(); | |
5823 stubName = "cipherBlockChaining_encryptAESCrypt"; | |
5824 break; | |
5825 case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: | |
5826 stubAddr = StubRoutines::cipherBlockChaining_decryptAESCrypt(); | |
5827 stubName = "cipherBlockChaining_decryptAESCrypt"; | |
5828 break; | |
5829 } | |
5830 if (stubAddr == NULL) return false; | |
5831 | |
5832 | |
5833 // Restore the stack and pop off the arguments. | |
5834 int nargs = 6; // this + oop/offset + len + oop/offset | |
5835 assert(callee()->signature()->size() == nargs-1, "wrong number of arguments"); | |
5836 Node *cipherBlockChaining_object = argument(0); | |
5837 Node *src = argument(1); | |
5838 Node *src_offset = argument(2); | |
5839 Node *len = argument(3); | |
5840 Node *dest = argument(4); | |
5841 Node *dest_offset = argument(5); | |
5842 | |
5843 // (1) src and dest are arrays. | |
5844 const Type* src_type = src->Value(&_gvn); | |
5845 const Type* dest_type = dest->Value(&_gvn); | |
5846 const TypeAryPtr* top_src = src_type->isa_aryptr(); | |
5847 const TypeAryPtr* top_dest = dest_type->isa_aryptr(); | |
5848 assert (top_src != NULL && top_src->klass() != NULL | |
5849 && top_dest != NULL && top_dest->klass() != NULL, "args are strange"); | |
5850 | |
5851 // checks are the responsibility of the caller | |
5852 Node* src_start = src; | |
5853 Node* dest_start = dest; | |
5854 if (src_offset != NULL || dest_offset != NULL) { | |
5855 assert(src_offset != NULL && dest_offset != NULL, ""); | |
5856 src_start = array_element_address(src, src_offset, T_BYTE); | |
5857 dest_start = array_element_address(dest, dest_offset, T_BYTE); | |
5858 } | |
5859 | |
5860 // if we are in this set of code, we "know" the embeddedCipher is an AESCrypt object | |
5861 // (because of the predicated logic executed earlier). | |
5862 // so we cast it here safely. | |
5863 // this requires a newer class file that has this array as littleEndian ints, otherwise we revert to java | |
5864 | |
5865 Node* embeddedCipherObj = load_field_from_object(cipherBlockChaining_object, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false); | |
5866 if (embeddedCipherObj == NULL) return false; | |
5867 | |
5868 // cast it to what we know it will be at runtime | |
5869 const TypeInstPtr* tinst = _gvn.type(cipherBlockChaining_object)->isa_instptr(); | |
5870 assert(tinst != NULL, "CBC obj is null"); | |
5871 assert(tinst->klass()->is_loaded(), "CBC obj is not loaded"); | |
5872 ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); | |
5873 if (!klass_AESCrypt->is_loaded()) return false; | |
5874 | |
5875 ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); | |
5876 const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_AESCrypt); | |
5877 const TypeOopPtr* xtype = aklass->as_instance_type(); | |
5878 Node* aescrypt_object = new(C) CheckCastPPNode(control(), embeddedCipherObj, xtype); | |
5879 aescrypt_object = _gvn.transform(aescrypt_object); | |
5880 | |
5881 // we need to get the start of the aescrypt_object's expanded key array | |
5882 Node* k_start = get_key_start_from_aescrypt_object(aescrypt_object); | |
5883 if (k_start == NULL) return false; | |
5884 | |
5885 // similarly, get the start address of the r vector | |
5886 Node* objRvec = load_field_from_object(cipherBlockChaining_object, "r", "[B", /*is_exact*/ false); | |
5887 if (objRvec == NULL) return false; | |
5888 Node* r_start = array_element_address(objRvec, intcon(0), T_BYTE); | |
5889 | |
5890 // Call the stub, passing src_start, dest_start, k_start, r_start and src_len | |
5891 make_runtime_call(RC_LEAF|RC_NO_FP, | |
5892 OptoRuntime::cipherBlockChaining_aescrypt_Type(), | |
5893 stubAddr, stubName, TypePtr::BOTTOM, | |
5894 src_start, dest_start, k_start, r_start, len); | |
5895 | |
5896 // return is void so no result needs to be pushed | |
5897 | |
5898 return true; | |
5899 } | |
5900 | |
5901 //------------------------------get_key_start_from_aescrypt_object----------------------- | |
5902 Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { | |
5903 Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I", /*is_exact*/ false); | |
5904 assert (objAESCryptKey != NULL, "wrong version of com.sun.crypto.provider.AESCrypt"); | |
5905 if (objAESCryptKey == NULL) return (Node *) NULL; | |
5906 | |
5907 // now have the array, need to get the start address of the K array | |
5908 Node* k_start = array_element_address(objAESCryptKey, intcon(0), T_INT); | |
5909 return k_start; | |
5910 } | |
5911 | |
5912 //----------------------------inline_cipherBlockChaining_AESCrypt_predicate---------------------------- | |
5913 // Return node representing slow path of predicate check. | |
5914 // the pseudo code we want to emulate with this predicate is: | |
5915 // for encryption: | |
5916 // if (embeddedCipherObj instanceof AESCrypt) do_intrinsic, else do_javapath | |
5917 // for decryption: | |
5918 // if ((embeddedCipherObj instanceof AESCrypt) && (cipher!=plain)) do_intrinsic, else do_javapath | |
5919 // note cipher==plain is more conservative than the original java code but that's OK | |
5920 // | |
5921 Node* LibraryCallKit::inline_cipherBlockChaining_AESCrypt_predicate(bool decrypting) { | |
5922 // First, check receiver for NULL since it is virtual method. | |
5923 int nargs = arg_size(); | |
5924 Node* objCBC = argument(0); | |
5925 _sp += nargs; | |
5926 objCBC = do_null_check(objCBC, T_OBJECT); | |
5927 _sp -= nargs; | |
5928 | |
5929 if (stopped()) return NULL; // Always NULL | |
5930 | |
5931 // Load embeddedCipher field of CipherBlockChaining object. | |
5932 Node* embeddedCipherObj = load_field_from_object(objCBC, "embeddedCipher", "Lcom/sun/crypto/provider/SymmetricCipher;", /*is_exact*/ false); | |
5933 | |
5934 // get AESCrypt klass for instanceOf check | |
5935 // AESCrypt might not be loaded yet if some other SymmetricCipher got us to this compile point | |
5936 // will have same classloader as CipherBlockChaining object | |
5937 const TypeInstPtr* tinst = _gvn.type(objCBC)->isa_instptr(); | |
5938 assert(tinst != NULL, "CBCobj is null"); | |
5939 assert(tinst->klass()->is_loaded(), "CBCobj is not loaded"); | |
5940 | |
5941 // we want to do an instanceof comparison against the AESCrypt class | |
5942 ciKlass* klass_AESCrypt = tinst->klass()->as_instance_klass()->find_klass(ciSymbol::make("com/sun/crypto/provider/AESCrypt")); | |
5943 if (!klass_AESCrypt->is_loaded()) { | |
5944 // if AESCrypt is not even loaded, we never take the intrinsic fast path | |
5945 Node* ctrl = control(); | |
5946 set_control(top()); // no regular fast path | |
5947 return ctrl; | |
5948 } | |
5949 ciInstanceKlass* instklass_AESCrypt = klass_AESCrypt->as_instance_klass(); | |
5950 | |
5951 _sp += nargs; // gen_instanceof might do an uncommon trap | |
5952 Node* instof = gen_instanceof(embeddedCipherObj, makecon(TypeKlassPtr::make(instklass_AESCrypt))); | |
5953 _sp -= nargs; | |
5954 Node* cmp_instof = _gvn.transform(new (C) CmpINode(instof, intcon(1))); | |
5955 Node* bool_instof = _gvn.transform(new (C) BoolNode(cmp_instof, BoolTest::ne)); | |
5956 | |
5957 Node* instof_false = generate_guard(bool_instof, NULL, PROB_MIN); | |
5958 | |
5959 // for encryption, we are done | |
5960 if (!decrypting) | |
5961 return instof_false; // even if it is NULL | |
5962 | |
5963 // for decryption, we need to add a further check to avoid | |
5964 // taking the intrinsic path when cipher and plain are the same | |
5965 // see the original java code for why. | |
5966 RegionNode* region = new(C) RegionNode(3); | |
5967 region->init_req(1, instof_false); | |
5968 Node* src = argument(1); | |
5969 Node *dest = argument(4); | |
5970 Node* cmp_src_dest = _gvn.transform(new (C) CmpPNode(src, dest)); | |
5971 Node* bool_src_dest = _gvn.transform(new (C) BoolNode(cmp_src_dest, BoolTest::eq)); | |
5972 Node* src_dest_conjoint = generate_guard(bool_src_dest, NULL, PROB_MIN); | |
5973 region->init_req(2, src_dest_conjoint); | |
5974 | |
5975 record_for_igvn(region); | |
5976 return _gvn.transform(region); | |
5977 | |
5978 } | |
5979 | |
5980 |