2012-12-18 24 views
11

मैं एएसएम उपयोग कर रहा हूँ और की तरह कुछ को फिर से लिखने के लिए चाहते हैं कहा जाता है इंजेक्शनएक जावा विधि _before_ एक और तरीका

someMethod().injectedMethod(arg).targetMethod(args...) 

दिक्कत यह है कि मैं क्या पता नहीं है है पहले विधि है, मुझे केवल लक्ष्य विधि पता है (इसलिए someMethod() ढूंढना और इसके बाद इंजेक्शन करना एक विकल्प नहीं है)।

मेरे पास लक्ष्य पद्धति के कई संस्करण भी हैं, पैरामीटर के विभिन्न सेट के साथ मैं इसे काम करना चाहता हूं।

एएसएम मैं कर सकते हैं आसानी से उपयोग करते हुए लक्ष्य विधि मंगलाचरण लगता है, लेकिन दुर्भाग्य से उस बिंदु पर संकार्य ढेर है:

[ argN, ..., arg1, instance, ... ] 

और जब मैं कितनी दूर नीचे उदाहरण हो जाएगा काम कर सकते हैं, वहाँ कोई बाईटकोड मैं है इंजेक्ट कर सकते हैं कि इसे पढ़ा जाएगा। मुझे पता है कि आप इसे डुप्लिकेशंस के साथ चाल का उपयोग करके 4 पैरामीटर तक कर सकते हैं, लेकिन मुझे एक सामान्य समाधान की आवश्यकता है।

मैं स्थानीय चर का एक गुच्छा जोड़ सकता हूं और स्टैक से सबकुछ कॉपी कर सकता हूं, उदाहरण की ओर इशारा करता हूं और सबकुछ वापस रखता हूं, लेकिन यह एक रनटाइम अक्षमता है जिसे मैं वास्तव में नहीं चाहता हूं।

मुझे क्या लगता है कि यह काम करेगा यदि मैं ट्रैक कर सकता हूं कि कौन सा निर्देश स्टैक्स पर इंस्टेंस पॉइंटर डालने के लिए ज़िम्मेदार था, और फिर मैं लक्ष्य विधि आमंत्रण के बजाय वहां अपना विधि आमंत्रण इंजेक्ट कर सकता था। हालांकि मुझे ऐसा करने में मेरी मदद करने के लिए कुछ भी खोजने में कोई भाग्य नहीं है।

मुझे पता है कि AspectJ जैसी चीजें इसके लिए अनुमति देती हैं, लेकिन इसे लोड करने के रूप में बहुत से वर्गों के लिए ऐसा करना है और AspectJ बहुत धीमी है।

क्या कोई मुझे एएसएम के शीर्ष पर बने विश्लेषण टूल पर इंगित कर सकता है जो मुझे ऐसा करने दे सकता है या कोई भी किसी विधि से पहले एक विधि कॉल इंजेक्ट करने के लिए बेहतर दृष्टिकोण के बारे में सोच सकता है?

+1

मुझे यह नहीं मिला, क्या आपको वास्तव में एएसएम का उपयोग करने की आवश्यकता है? क्योंकि ऐसा लगता है कि आप मौजूदा जार को हैक करने की कोशिश कर रहे हैं। इसके लिए इसे कम करना बेहतर होगा ......... यदि नहीं, और आप जावा एप्लिकेशन लिख रहे हैं, तो क्या आप इसके लिए एग्रीगेशन का उपयोग नहीं कर सकते? – fredcrs

+0

मैं कक्षाओं को विघटित नहीं कर सकता क्योंकि मैं इसे क्लास लोड समय पर एक जावावांट के रूप में ही लगा सकता हूं। मैं न तो 'मौजूदा जार हैकिंग' या 'जावा एप्लिकेशन लिखना' हूं; मैं कक्षाओं में बाइटकोड इंजेक्शन कर रहा हूं क्योंकि वे लोड होते हैं। – David

+0

मैंने स्कूल में रहते हुए [सूट] (http://www.sable.mcgill.ca/soot/) के साथ काम किया है और वास्तव में इस तरह की चीजें की हैं (ठीक है शायद थोड़ा कम जटिल)। जरा देखो तो। दुर्भाग्यवश, मुझे नहीं पता कि यह एएसएम के शीर्ष पर बनाया गया है या नहीं। दिमाग में आने वाला एकमात्र अन्य विकल्प AspectJ है। – arin

उत्तर

1

सामान्य स्थिति में आप अस्थायी स्थानीय चर में स्टैक से मूल्यों को ऑफ़लोड कर सकते हैं। एएसएम कॉमन्स पैकेज से LocalVariableSorter एडाप्टर इसे वास्तविक बनाता है। लेकिन वास्तविकता विधियों में अधिक से अधिक 4 तर्क एक दुर्लभ मामला है। किसी भी तरह से यह अभी भी बहुत आसान और अधिक ठोस है तो रनटाइम पर पूर्ण उड़ा डेटाफ्लो विश्लेषण कर रहा है।

एएसएम का org.objectweb.asm.tree.analysis डेटा प्रवाह विश्लेषण के लिए सुविधा प्रदान करता है, उदाहरण के लिए आप SourceInterpreter का उपयोग करके प्रत्येक चर और स्टैक स्लॉट पर दिए गए मानों को ट्रैक करने के लिए उपयोग कर सकते हैं। अधिक जानकारी के लिए ASM User Guide देखें।

+0

रनटाइम पर एक पूर्ण उड़ाए गए डेटा विश्लेषण से आपका क्या मतलब है? और आप यह कैसे करेंगे? – vijay

+1

मैंने कुछ स्पष्टीकरण और दस्तावेज़ीकरण के लिए सीधे लिंक जोड़े हैं। –

2

यदि मैं आपके प्रश्न को सही तरीके से समझता हूं, तो मैंने वही हासिल किया है जो आप करना चाहते हैं लेकिन एक अलग तरीके से।

एएसएम घटना संचालित बाइट कोड संशोधन का उपयोग करते हुए, मैंने सबसे पहले सभी का नाम बदलकर कुछ विधि (तर्क, तर्क, तर्क) copyOf_someMethod (arg, arg, arg) में किया है। फिर मैंने कुछ विधि (arg, arg, arg) नामक एक नई विधि बनाई जिसने कुछ प्रसंस्करण किया और फिर copyOf_someMethod (arg, arg, arg) कहा जाता है।

मैं विधि ClassVisitor मैं कार्यान्वित की विधि visitMethod (..) में नाम बदलने किया:

MethodVisitor methodVisitor = 
    super.visitMethod(
     methodAccess, "copyOf_" + methodName, methodDesc, 
      methodSignature, methodExceptions); 

return methodVisitor; 

visitMethod में (..) मैं भी वर्ग के लिए तैयार चर के सभी विधि हस्ताक्षर विवरण संग्रहीत visitEnd() विधि में उपयोग किया जाना चाहिए।

मैं वास्तव में एक MethodDetail वस्तु में विधि का विवरण संग्रहीत और एक कतार में रखा:

private Queue<MethodDetail> methodDetails = new LinkedList<MethodDetail>(); 

मैं someMethod के नए कार्यान्वयन बनाया (आर्ग, आर्ग, आर्ग) की विधि visitEnd() का उपयोग क्लासविजिटर I लागू किया गया। मैंने visitEnd() विधि में कोड बनाने के लिए कोड उत्पन्न करने के लिए ASMFier का उपयोग किया। कार्यान्वयन ने उन विवरणों का उपयोग किया जो मैंने पहले संग्रहीत किया था। विधि (..)। नए कार्यान्वयन ने कुछ प्रसंस्करण किया और फिर copyOf_someMethod() कहा जाता है। VisitEnd() विधि में मैंने कतार के सभी विधि विवरण और एएसएम कोड नामक प्रत्येक विधि के लिए पॉप अप किया था जिसे मैंने पहले एएसएमएफयर द्वारा जेनरेट किया था।

इस डिज़ाइन का उपयोग करके मैंने एक विधि के लिए प्रॉक्सी बनाई थी जिसने कुछ प्रसंस्करण किया और फिर मूल विधि को बुलाया। ध्यान दें कि मूल विधि का नाम बदलकर copyOf_someMethod (..) कर दिया गया था। ध्यान दें कि मैंने मूल विधि के लिए एक नया कार्यान्वयन प्रदान किया जो प्रॉक्सी के रूप में कार्य करता था।

एकाधिक तर्कों का समर्थन करने के लिए मैंने 1 arg, 2 arg, 3 arg, e.t.c. के लिए अलग कोड उत्पन्न करने के लिए ASMFier का उपयोग किया। मैंने 7 तर्कों का समर्थन किया और एक असमर्थित अपवाद फेंक दिया अगर विधि का प्रक्षेपण किया गया 7 से अधिक तर्क थे। विज़िट एंड (..) विधि में मैंने मूल विधि के कितने विधि तर्कों के आधार पर अलग कोड (जिसे एएसएमएफयर द्वारा उत्पन्न किया गया था) कहा जाता है।

मैंने क्लास लोडिंग को बाधित करने और बाइट्स को संशोधित करने के लिए एक जावाजेंट का उपयोग किया।

जैसा कि मैं एएसएम के लिए नया हूं, शायद मैं आपके प्रश्न को ठीक से समझ नहीं पाया - हालांकि यदि आपका प्रश्न प्रॉक्सी बनाने के बारे में था जो कुछ प्रसंस्करण करता है और फिर मूल विधि को कॉल करता है तो मेरा समाधान काम करता है। यह धीमा प्रतीत नहीं होता था। वर्ग के लिए क्लास लोड अप समय के तरीकों से छुटकारा पाने के लिए बाइट कोड संशोधन के मुकाबले ज्यादा धीमी नहीं थी। पेश किए गए कोड की रनटाइम गति धीमी नहीं थी, एएसएमएफयर द्वारा उत्पन्न एएसएम कोड बहुत तेज़ प्रतीत होता है।

चीयर्स

0

org.objectweb.asm.tree.analysis में देखो। SourceIterpreter आपको उन निर्देशों को देना चाहिए जो ढेर पर मूल्य डालते हैं।