001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.bytecode;
006:
007: import com.tc.asm.ClassAdapter;
008: import com.tc.asm.ClassVisitor;
009: import com.tc.asm.FieldVisitor;
010: import com.tc.asm.Label;
011: import com.tc.asm.MethodVisitor;
012: import com.tc.asm.Opcodes;
013: import com.tc.asm.Type;
014: import com.tc.aspectwerkz.reflect.ClassInfo;
015: import com.tc.aspectwerkz.reflect.FieldInfo;
016: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
017: import com.tc.object.Portability;
018: import com.tc.object.config.TransparencyClassSpec;
019:
020: import java.lang.reflect.Method;
021: import java.lang.reflect.Modifier;
022: import java.util.Arrays;
023: import java.util.Collection;
024: import java.util.Collections;
025: import java.util.HashMap;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.LinkedHashSet;
029: import java.util.Map;
030: import java.util.Set;
031:
032: /**
033: * Common base class for Terracotta class adapters
034: */
035: public abstract class ClassAdapterBase extends ClassAdapter implements
036: Opcodes {
037: public static final String MANAGED_FIELD_NAME = ByteCodeUtil.TC_FIELD_PREFIX
038: + "MANAGED";
039: public static final String MANAGED_FIELD_TYPE = "Lcom/tc/object/TCObject;";
040: public static final String MANAGED_METHOD = ByteCodeUtil.TC_METHOD_PREFIX
041: + "managed";
042: public static final String IS_MANAGED_METHOD = ByteCodeUtil.TC_METHOD_PREFIX
043: + "isManaged";
044: public static final String IS_MANAGED_DESCRIPTION = "()Z";
045:
046: public static final String VALUES_GETTER = ByteCodeUtil.VALUES_GETTER;
047: public static final String VALUES_GETTER_DESCRIPTION = ByteCodeUtil.VALUES_GETTER_DESCRIPTION;
048:
049: public static final String VALUES_SETTER = ByteCodeUtil.VALUES_SETTER;
050: public static final String VALUES_SETTER_DESCRIPTION = ByteCodeUtil.VALUES_SETTER_DESCRIPTION;
051:
052: public static final String MANAGED_VALUES_GETTER = ByteCodeUtil.MANAGED_VALUES_GETTER;
053: public static final String MANAGED_VALUES_GETTER_DESCRIPTION = ByteCodeUtil.MANAGED_VALUES_GETTER_DESCRIPTION;
054:
055: public static final String MANAGED_VALUES_SETTER = ByteCodeUtil.MANAGED_VALUES_SETTER;
056:
057: private static final String LOGICAL_TYPE_DELEGATE_FIELD_NAME_PREFIX = "__delegate_tc_";
058: private static final int LOGICAL_TYPE_DELEGATE_FIELD_MODIFIER = ACC_PRIVATE
059: + ACC_TRANSIENT;
060:
061: private static final Set ALWAYS_REWRITE_IF_PRESENT = getAlwaysRewrite();
062:
063: private final Map fields = new HashMap();
064: protected final InstrumentationSpec spec;
065: private final Portability portability;
066: private boolean hasVisitedDelegateField = false;
067:
068: public static String getDelegateFieldName(
069: String logicalExtendingClassName) {
070: return LOGICAL_TYPE_DELEGATE_FIELD_NAME_PREFIX
071: + logicalExtendingClassName.replace('.', '_').replace(
072: '/', '_').replace('$', '_');
073: }
074:
075: private static Set getAlwaysRewrite() {
076: Set s = new HashSet();
077: s.addAll(getInterfaceMethodDescriptions(Manageable.class));
078: s
079: .addAll(getInterfaceMethodDescriptions(TransparentAccess.class));
080: return Collections.unmodifiableSet(s);
081: }
082:
083: public static boolean isDelegateFieldName(String fieldName) {
084: return fieldName
085: .startsWith(LOGICAL_TYPE_DELEGATE_FIELD_NAME_PREFIX);
086: }
087:
088: protected TransparencyClassSpec getTransparencyClassSpec() {
089: return spec.getTransparencyClassSpec();
090: }
091:
092: protected InstrumentationSpec getInstrumentationSpec() {
093: return spec;
094: }
095:
096: private boolean isRoot(String fieldName) {
097: FieldInfo fieldInfo = getInstrumentationSpec().getFieldInfo(
098: fieldName);
099: if (fieldInfo == null) {
100: return false;
101: }
102:
103: return getTransparencyClassSpec().isRootInThisClass(fieldInfo);
104: }
105:
106: public ClassAdapterBase(ClassInfo classInfo,
107: TransparencyClassSpec spec2, ClassVisitor delegate,
108: ManagerHelper mgrHelper, ClassLoader caller, Portability p) {
109: super (delegate);
110: this .portability = p;
111: this .spec = new InstrumentationSpec(classInfo, spec2,
112: mgrHelper, caller);
113: }
114:
115: public final void visit(int version, int access, String name,
116: String signature, String super Name, String[] interfaces) {
117: spec.initialize(version, access, name, signature, super Name,
118: interfaces, portability);
119:
120: if (spec.isClassNotAdaptable()) {
121: super .visit(version, access, name, signature, super Name,
122: interfaces);
123: return;
124: }
125:
126: if (spec.isClassPortable()) {
127: interfaces = getNewInterfacesForPortableObject(interfaces);
128: }
129:
130: basicVisit(version, access, name, signature, super Name,
131: interfaces);
132: }
133:
134: private void visitDelegateFieldIfNecessary() {
135: if (!hasVisitedDelegateField) {
136: hasVisitedDelegateField = true;
137: String super ClassNameSlashes = spec
138: .getSuperClassNameSlashes();
139: String delegateFieldName = getDelegateFieldName(super ClassNameSlashes);
140: String delegateFieldType = "L" + super ClassNameSlashes
141: + ";";
142: visitField(LOGICAL_TYPE_DELEGATE_FIELD_MODIFIER,
143: delegateFieldName, delegateFieldType, null, null);
144: }
145: }
146:
147: private String[] getNewInterfacesForPortableObject(
148: String[] interfaces) {
149: Set ifaces = new LinkedHashSet(Arrays.asList(interfaces));
150: if (!ifaces.contains(ByteCodeUtil.MANAGEABLE_CLASS)) {
151: ifaces.add(ByteCodeUtil.MANAGEABLE_CLASS);
152: }
153:
154: if (!spec.isLogical()
155: && !ifaces
156: .contains(ByteCodeUtil.TRANSPARENT_ACCESS_CLASS)) {
157: ifaces.add(ByteCodeUtil.TRANSPARENT_ACCESS_CLASS);
158: }
159:
160: return (String[]) ifaces.toArray(interfaces);
161: }
162:
163: public final FieldVisitor visitField(int access, String name,
164: String desc, String signature, Object value) {
165: spec.handleSubclassOfLogicalClassWithFieldsIfNecessary(access);
166: if (spec.needDelegateField()) {
167: visitDelegateFieldIfNecessary();
168: }
169:
170: // always add a known definition for this field if it already exists
171: if (MANAGED_FIELD_NAME.equals(name)) {
172: return null;
173: }
174:
175: spec.recordExistingFields(name, desc, signature);
176:
177: if (spec.isClassNotAdaptable()
178: || name.startsWith(ByteCodeUtil.TC_FIELD_PREFIX)) {
179: return super .visitField(access, name, desc, signature,
180: value);
181: }
182: if (!Modifier.isStatic(access)) {
183: fields.put(name, desc);
184: }
185: return basicVisitField(access, name, desc, signature, value);
186: }
187:
188: public final MethodVisitor visitMethod(int access, String name,
189: String desc, String signature, String[] exceptions) {
190: spec.shouldProceedInstrumentation(access, name, desc);
191:
192: if (spec.isClassNotAdaptable()) {
193: return super .visitMethod(access, name, desc, signature,
194: exceptions);
195: }
196: MethodVisitor mv;
197:
198: // always add a known implementation for these methods even if they already exist
199: if (ALWAYS_REWRITE_IF_PRESENT.contains(name + desc)) {
200: return null;
201: }
202:
203: spec.recordExistingMethods(name, desc, signature);
204:
205: if (spec.shouldVisitMethod(access, name)) {
206: mv = basicVisitMethod(access, name, desc, signature,
207: exceptions);
208: if (spec.hasDelegatedToLogicalClass()) {
209: String logicalExtendingClassName = spec
210: .getSuperClassNameSlashes();
211: mv = new LogicalClassSerializationAdapter.LogicalSubclassSerializationMethodAdapter(
212: mv, name + desc, spec.getClassNameSlashes(),
213: logicalExtendingClassName,
214: getDelegateFieldName(logicalExtendingClassName));
215: }
216: } else {
217: mv = super .visitMethod(access, name, desc, signature,
218: exceptions);
219: }
220:
221: return mv;
222: }
223:
224: private void revisitLogicalSubclassDefinition() {
225: spec.moveToLogicalIfNecessary();
226:
227: String[] interfaces = spec.getClassInterfaces();
228: interfaces = getNewInterfacesForPortableObject(interfaces);
229:
230: basicVisit(spec.getClassVersion(), spec.getClassAccess(), spec
231: .getClassNameSlashes(), spec.getClassSignature(), spec
232: .getSuperClassNameSlashes(), interfaces);
233: }
234:
235: public final void visitEnd() {
236: if (spec.isClassNotAdaptable()) {
237: super .visitEnd();
238: return;
239: }
240:
241: if (spec.isSubclassofLogicalClass()) {
242: // If this is a subclass of a logical class, we need to determine if we need the
243: // TransparentAccess interface, depending if the subclass has defined any field or
244: // not.
245: revisitLogicalSubclassDefinition();
246: }
247:
248: // We will add overriding method if there is any if this is a subclass of a logical
249: // class.
250: addOverridenLogicalMethods();
251:
252: addRetrieveValuesMethod();
253: addSetValueMethod();
254: addRetrieveManagedValueMethod();
255: addSetManagedValueMethod();
256:
257: // Condition for generating __tc_managed() method and $__tc_managed field should be the same.
258: if (spec.isManagedFieldNeeded()) {
259: addCachedManagedMethods();
260:
261: super .visitField(ACC_PRIVATE | ACC_VOLATILE | ACC_TRANSIENT
262: | ACC_SYNTHETIC, MANAGED_FIELD_NAME,
263: MANAGED_FIELD_TYPE, null, null);
264: }
265:
266: basicVisitEnd();
267: }
268:
269: private void addOverridenLogicalMethods() {
270: Collection needToOverrideMethods = spec
271: .getShouldOverrideMethods();
272: for (Iterator i = needToOverrideMethods.iterator(); i.hasNext();) {
273: Method m = (Method) i.next();
274: int modifier = m.getModifiers();
275: String methodName = m.getName();
276: if (!spec.shouldVisitMethod(modifier, methodName)
277: || Modifier.isFinal(modifier)) {
278: continue;
279: }
280:
281: String methodDesc = Type.getMethodDescriptor(m);
282: Type returnType = Type.getReturnType(m);
283:
284: Class[] exceptionTypes = m.getExceptionTypes();
285: String[] exceptions = new String[exceptionTypes.length];
286: for (int j = 0; j < exceptionTypes.length; j++) {
287: exceptions[j] = Type.getInternalName(exceptionTypes[j]);
288: }
289:
290: String logicalExtendingClassName = spec
291: .getSuperClassNameSlashes();
292:
293: MethodVisitor mv = cv.visitMethod(modifier & ~ACC_ABSTRACT,
294: methodName, methodDesc, null, exceptions);
295: mv.visitVarInsn(ALOAD, 0);
296: mv
297: .visitMethodInsn(
298: INVOKESPECIAL,
299: spec.getClassNameSlashes(),
300: ByteCodeUtil
301: .fieldGetterMethod(getDelegateFieldName(logicalExtendingClassName)),
302: "()L" + logicalExtendingClassName + ";");
303: ByteCodeUtil
304: .pushMethodArguments(ACC_PUBLIC, methodDesc, mv);
305: mv.visitMethodInsn(INVOKEVIRTUAL,
306: logicalExtendingClassName, methodName, methodDesc);
307:
308: mv.visitInsn(returnType.getOpcode(IRETURN));
309: mv.visitMaxs(0, 0);
310: mv.visitEnd();
311: }
312: if (spec.hasDelegatedToLogicalClass()) {
313: addReadObjectMethod();
314: addWriteObjectMethod();
315: addSerializationOverrideMethod();
316: }
317: }
318:
319: private void addSerializationOverrideMethod() {
320: LogicalClassSerializationAdapter
321: .addCheckSerializationOverrideMethod(cv, true);
322: }
323:
324: private void addWriteObjectMethod() {
325: if (!spec.isWriteObjectMethodNeeded()) {
326: return;
327: }
328: String logicalExtendingClassName = spec
329: .getSuperClassNameSlashes();
330:
331: MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "writeObject",
332: "(Ljava/io/ObjectOutputStream;)V", null,
333: new String[] { "java/io/IOException" });
334: mv.visitCode();
335: LogicalClassSerializationAdapter
336: .addDelegateFieldWriteObjectCode(mv, spec
337: .getClassNameSlashes(),
338: logicalExtendingClassName,
339: getDelegateFieldName(logicalExtendingClassName));
340: mv.visitInsn(RETURN);
341: mv.visitMaxs(0, 0);
342: mv.visitEnd();
343: }
344:
345: private void addReadObjectMethod() {
346: if (!spec.isReadObjectMethodNeeded()) {
347: return;
348: }
349: String logicalExtendingClassName = spec
350: .getSuperClassNameSlashes();
351:
352: MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "readObject",
353: "(Ljava/io/ObjectInputStream;)V", null, new String[] {
354: "java/io/IOException",
355: "java/lang/ClassNotFoundException" });
356: mv.visitCode();
357: LogicalClassSerializationAdapter
358: .addDelegateFieldReadObjectCode(mv, spec
359: .getClassNameSlashes(),
360: logicalExtendingClassName,
361: getDelegateFieldName(logicalExtendingClassName));
362: mv.visitInsn(RETURN);
363: mv.visitMaxs(0, 0);
364: mv.visitEnd();
365: }
366:
367: private void addCachedManagedMethods() {
368: if (spec.isManagedMethodsNeeded()) {
369: // add getter
370: MethodVisitor mv = super .visitMethod(ACC_PUBLIC
371: | ACC_SYNTHETIC, MANAGED_METHOD, "()"
372: + MANAGED_FIELD_TYPE, null, null);
373: mv.visitVarInsn(ALOAD, 0);
374: mv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
375: MANAGED_FIELD_NAME, MANAGED_FIELD_TYPE);
376: mv.visitInsn(ARETURN);
377: mv.visitMaxs(0, 0);
378:
379: // add setter
380: mv = super .visitMethod(ACC_PUBLIC | ACC_SYNTHETIC,
381: MANAGED_METHOD, "(" + MANAGED_FIELD_TYPE + ")V",
382: null, null);
383: mv.visitVarInsn(ALOAD, 0);
384: mv.visitVarInsn(ALOAD, 1);
385: mv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(),
386: MANAGED_FIELD_NAME, MANAGED_FIELD_TYPE);
387: mv.visitInsn(RETURN);
388: mv.visitMaxs(0, 0);
389:
390: // add isManaged() method
391: // XXX::FIXME:: This method need to handle TCClonableObjects and TCNonDistributableObjects
392: mv = super .visitMethod(ACC_PUBLIC | ACC_SYNTHETIC,
393: IS_MANAGED_METHOD, IS_MANAGED_DESCRIPTION, null,
394: null);
395: mv.visitVarInsn(ALOAD, 0);
396: mv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
397: MANAGED_FIELD_NAME, MANAGED_FIELD_TYPE);
398: Label l1 = new Label();
399: mv.visitJumpInsn(IFNULL, l1);
400: mv.visitInsn(ICONST_1);
401: mv.visitInsn(IRETURN);
402: mv.visitLabel(l1);
403: mv.visitInsn(ICONST_0);
404: mv.visitInsn(IRETURN);
405: mv.visitMaxs(1, 1);
406: }
407: }
408:
409: /**
410: * Creates a method that takes all of the fields in the class and the super classes and puts them into the passed in
411: * hashmap
412: */
413: private void addRetrieveValuesMethod() {
414: if (spec.isValuesGetterMethodNeeded()) {
415: MethodVisitor mv = super .visitMethod(ACC_PUBLIC
416: | ACC_SYNTHETIC, VALUES_GETTER,
417: VALUES_GETTER_DESCRIPTION, null, null);
418: if (!portability.isInstrumentationNotNeeded(spec
419: .getSuperClassNameDots())
420: && getTransparencyClassSpec()
421: .hasPhysicallyPortableSpecs(
422: AsmClassInfo.getClassInfo(spec
423: .getSuperClassNameDots(),
424: spec.getClassInfo()
425: .getClassLoader()))) {
426: mv.visitVarInsn(ALOAD, 0);
427: mv.visitVarInsn(ALOAD, 1);
428: mv.visitMethodInsn(INVOKESPECIAL, spec
429: .getSuperClassNameSlashes(), VALUES_GETTER,
430: VALUES_GETTER_DESCRIPTION);
431: }
432:
433: for (Iterator i = fields.keySet().iterator(); i.hasNext();) {
434: String fieldName = (String) i.next();
435: String fieldDescription = (String) fields
436: .get(fieldName);
437:
438: mv.visitVarInsn(ALOAD, 1);
439: mv.visitLdcInsn(spec.getClassNameDots() + "."
440: + fieldName);
441: addValueToStackForField(mv, fieldName, fieldDescription);
442: mv
443: .visitMethodInsn(INVOKEINTERFACE,
444: "java/util/Map", "put",
445: "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
446: mv.visitInsn(POP);
447: }
448: mv.visitInsn(RETURN);
449: mv.visitMaxs(0, 0);
450: }
451: }
452:
453: private void addRetrieveManagedValueMethod() {
454: if (spec.isManagedValuesGetterMethodNeeded()) {
455: MethodVisitor mv = super .visitMethod(ACC_PUBLIC
456: | ACC_SYNTHETIC, MANAGED_VALUES_GETTER,
457: MANAGED_VALUES_GETTER_DESCRIPTION, null, null);
458:
459: for (Iterator i = fields.keySet().iterator(); i.hasNext();) {
460: String fieldName = (String) i.next();
461: String fieldDescription = (String) fields
462: .get(fieldName);
463: mv.visitVarInsn(ALOAD, 1);
464: mv.visitLdcInsn(spec.getClassNameDots() + "."
465: + fieldName);
466: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String",
467: "equals", "(Ljava/lang/Object;)Z");
468: Label l1 = new Label();
469: mv.visitJumpInsn(IFEQ, l1);
470:
471: if (ByteCodeUtil.isSynthetic(fieldName)) {
472: addValueToStackForField(mv, fieldName,
473: fieldDescription);
474: } else {
475: addManagedValueToStackForField(mv, fieldName,
476: fieldDescription);
477: }
478: mv.visitInsn(ARETURN);
479: mv.visitLabel(l1);
480: }
481:
482: if (!portability.isInstrumentationNotNeeded(spec
483: .getSuperClassNameDots())
484: && getTransparencyClassSpec()
485: .hasPhysicallyPortableSpecs(
486: AsmClassInfo.getClassInfo(spec
487: .getSuperClassNameDots(),
488: spec.getClassInfo()
489: .getClassLoader()))) {
490: mv.visitVarInsn(ALOAD, 0);
491: mv.visitVarInsn(ALOAD, 1);
492: mv.visitMethodInsn(INVOKESPECIAL, spec
493: .getSuperClassNameSlashes(),
494: MANAGED_VALUES_GETTER,
495: MANAGED_VALUES_GETTER_DESCRIPTION);
496: } else {
497: mv.visitInsn(ACONST_NULL);
498: }
499: mv.visitInsn(ARETURN);
500: mv.visitMaxs(0, 0);
501: }
502: }
503:
504: /**
505: * Creates a method that allows the setting of any field in this class or it's super classes.
506: */
507: private void addSetValueMethod() {
508: if (spec.isValuesSetterMethodNeeded()) {
509: MethodVisitor mv = super .visitMethod(ACC_PUBLIC
510: | ACC_SYNTHETIC, VALUES_SETTER,
511: VALUES_SETTER_DESCRIPTION, null, null);
512: Label l1 = new Label();
513: for (Iterator i = fields.keySet().iterator(); i.hasNext();) {
514: String fieldName = (String) i.next();
515: if (ByteCodeUtil.isTCSynthetic(fieldName)) {
516: continue;
517: }
518:
519: String fieldDescription = (String) fields
520: .get(fieldName);
521: Type t = Type.getType(fieldDescription);
522: mv.visitVarInsn(ALOAD, 1);
523: mv.visitLdcInsn(spec.getClassNameDots() + "."
524: + fieldName);
525: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String",
526: "equals", "(Ljava/lang/Object;)Z");
527: Label l2 = new Label();
528: mv.visitJumpInsn(IFEQ, l2);
529: mv.visitVarInsn(ALOAD, 0);
530: mv.visitVarInsn(ALOAD, 2);
531: if (t.getSort() != Type.OBJECT
532: && t.getSort() != Type.ARRAY) {
533: mv.visitTypeInsn(CHECKCAST, ByteCodeUtil
534: .sortToWrapperName(t.getSort()));
535: mv.visitMethodInsn(INVOKEVIRTUAL, ByteCodeUtil
536: .sortToWrapperName(t.getSort()),
537: ByteCodeUtil.sortToPrimitiveMethodName(t
538: .getSort()), "()"
539: + fieldDescription);
540: } else {
541: mv.visitTypeInsn(CHECKCAST,
542: convertToCheckCastDesc(fieldDescription));
543: }
544: mv.visitFieldInsn(PUTFIELD, spec.getClassNameSlashes(),
545: fieldName, fieldDescription);
546: mv.visitJumpInsn(GOTO, l1);
547: mv.visitLabel(l2);
548: }
549: if (!portability.isInstrumentationNotNeeded(spec
550: .getSuperClassNameDots())
551: && getTransparencyClassSpec()
552: .hasPhysicallyPortableSpecs(
553: AsmClassInfo.getClassInfo(spec
554: .getSuperClassNameDots(),
555: spec.getClassInfo()
556: .getClassLoader()))) {
557: mv.visitVarInsn(ALOAD, 0);
558: mv.visitVarInsn(ALOAD, 1);
559: mv.visitVarInsn(ALOAD, 2);
560: mv.visitMethodInsn(INVOKESPECIAL, spec
561: .getSuperClassNameSlashes(), VALUES_SETTER,
562: VALUES_SETTER_DESCRIPTION);
563: }
564: mv.visitLabel(l1);
565:
566: mv.visitInsn(RETURN);
567: mv.visitMaxs(0, 0);
568: }
569: }
570:
571: private void addSetManagedValueMethod() {
572: if (spec.isManagedValuesSetterMethodNeeded()) {
573: MethodVisitor mv = super .visitMethod(ACC_PUBLIC
574: | ACC_SYNTHETIC, MANAGED_VALUES_SETTER,
575: VALUES_SETTER_DESCRIPTION, null, null);
576:
577: Label l1 = new Label();
578: for (Iterator i = fields.keySet().iterator(); i.hasNext();) {
579: String fieldName = (String) i.next();
580: if (ByteCodeUtil.isSynthetic(fieldName)) {
581: continue;
582: }
583:
584: String fieldDescription = (String) fields
585: .get(fieldName);
586: Type t = Type.getType(fieldDescription);
587: mv.visitVarInsn(ALOAD, 1);
588: mv.visitLdcInsn(spec.getClassNameDots() + "."
589: + fieldName);
590: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String",
591: "equals", "(Ljava/lang/Object;)Z");
592: Label l2 = new Label();
593: mv.visitJumpInsn(IFEQ, l2);
594: mv.visitVarInsn(ALOAD, 0);
595: mv.visitVarInsn(ALOAD, 2);
596: if (t.getSort() != Type.OBJECT
597: && t.getSort() != Type.ARRAY) {
598: mv.visitTypeInsn(CHECKCAST, ByteCodeUtil
599: .sortToWrapperName(t.getSort()));
600: mv.visitMethodInsn(INVOKEVIRTUAL, ByteCodeUtil
601: .sortToWrapperName(t.getSort()),
602: ByteCodeUtil.sortToPrimitiveMethodName(t
603: .getSort()), "()"
604: + fieldDescription);
605: } else {
606: mv.visitTypeInsn(CHECKCAST,
607: convertToCheckCastDesc(fieldDescription));
608: }
609: mv.visitMethodInsn(INVOKEVIRTUAL, spec
610: .getClassNameSlashes(), ByteCodeUtil
611: .fieldSetterMethod(fieldName), "("
612: + fieldDescription + ")V");
613: mv.visitJumpInsn(GOTO, l1);
614: mv.visitLabel(l2);
615: }
616:
617: if (!portability.isInstrumentationNotNeeded(spec
618: .getSuperClassNameDots())
619: && getTransparencyClassSpec()
620: .hasPhysicallyPortableSpecs(
621: AsmClassInfo.getClassInfo(spec
622: .getSuperClassNameDots(),
623: spec.getClassInfo()
624: .getClassLoader()))) {
625: mv.visitVarInsn(ALOAD, 0);
626: mv.visitVarInsn(ALOAD, 1);
627: mv.visitVarInsn(ALOAD, 2);
628: mv.visitMethodInsn(INVOKESPECIAL, spec
629: .getSuperClassNameSlashes(),
630: MANAGED_VALUES_SETTER,
631: VALUES_SETTER_DESCRIPTION);
632: }
633:
634: mv.visitLabel(l1);
635: mv.visitInsn(RETURN);
636: mv.visitMaxs(0, 0);
637: }
638: }
639:
640: protected String convertToCheckCastDesc(String desc) {
641: if (desc.startsWith("["))
642: return desc;
643: return desc.substring(1, desc.length() - 1);
644: }
645:
646: private void addValueToStackForField(MethodVisitor mv,
647: String fieldName, String fieldDescription) {
648: Type t = Type.getType(fieldDescription);
649:
650: if (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY) {
651: ByteCodeUtil.pushThis(mv);
652: mv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
653: fieldName, fieldDescription);
654: } else {
655: mv.visitTypeInsn(NEW, ByteCodeUtil.sortToWrapperName(t
656: .getSort()));
657: mv.visitInsn(DUP);
658: ByteCodeUtil.pushThis(mv);
659: mv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
660: fieldName, fieldDescription);
661: mv.visitMethodInsn(INVOKESPECIAL, ByteCodeUtil
662: .sortToWrapperName(t.getSort()), "<init>", "("
663: + fieldDescription + ")V");
664: }
665: }
666:
667: private void addManagedValueToStackForField(MethodVisitor mv,
668: String fieldName, String fieldDescription) {
669: Type t = Type.getType(fieldDescription);
670: if (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY) {
671: ByteCodeUtil.pushThis(mv);
672: mv.visitMethodInsn(INVOKESPECIAL, spec
673: .getClassNameSlashes(), ByteCodeUtil
674: .fieldGetterMethod(fieldName), "()"
675: + fieldDescription);
676: } else {
677: mv.visitTypeInsn(NEW, ByteCodeUtil.sortToWrapperName(t
678: .getSort()));
679: mv.visitInsn(DUP);
680: ByteCodeUtil.pushThis(mv);
681: if (isRoot(fieldName)) {
682: mv.visitMethodInsn(INVOKESPECIAL, spec
683: .getClassNameSlashes(), ByteCodeUtil
684: .fieldGetterMethod(fieldName), "()"
685: + fieldDescription);
686: } else {
687: mv.visitFieldInsn(GETFIELD, spec.getClassNameSlashes(),
688: fieldName, fieldDescription);
689: }
690: mv.visitMethodInsn(INVOKESPECIAL, ByteCodeUtil
691: .sortToWrapperName(t.getSort()), "<init>", "("
692: + fieldDescription + ")V");
693: }
694: }
695:
696: protected void basicVisit(int version, int access, String name,
697: String signature, String super Name, String[] interfaces) {
698: // override me if you need to access to the standard visit() method
699: cv.visit(version, access, name, signature, super Name,
700: interfaces);
701: }
702:
703: protected FieldVisitor basicVisitField(int access, String name,
704: String desc, String signature, Object value) {
705: // override me if you need to access to the standard visitField() method
706: return cv.visitField(access, name, desc, signature, value);
707: }
708:
709: protected MethodVisitor basicVisitMethod(int access, String name,
710: String desc, String signature, String[] exceptions) {
711: // override me if you need to access to the standard visitMethod() method
712: return cv
713: .visitMethod(access, name, desc, signature, exceptions);
714: }
715:
716: protected void basicVisitEnd() {
717: // override me if you need to access to the standard visitMethod() method
718: cv.visitEnd();
719: }
720:
721: private static Collection getInterfaceMethodDescriptions(Class iface) {
722: Set rv = new HashSet();
723: Method[] methods = iface.getMethods();
724: for (int i = 0; i < methods.length; i++) {
725: Method method = methods[i];
726: rv.add(method.getName() + Type.getMethodDescriptor(method));
727: }
728:
729: return rv;
730: }
731:
732: }
|