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 org.terracotta.modules;
006:
007: import com.tc.asm.ClassAdapter;
008: import com.tc.asm.ClassVisitor;
009: import com.tc.asm.Label;
010: import com.tc.asm.MethodVisitor;
011: import com.tc.asm.Opcodes;
012: import com.tc.asm.Type;
013: import com.tc.asm.commons.LocalVariablesSorter;
014: import com.tc.object.bytecode.ByteCodeUtil;
015: import com.tc.object.bytecode.ClassAdapterFactory;
016: import com.tc.object.lockmanager.api.LockLevel;
017:
018: public class DSOUnsafeAdapter extends ClassAdapter implements Opcodes,
019: ClassAdapterFactory {
020:
021: public DSOUnsafeAdapter() {
022: super (null);
023: }
024:
025: private DSOUnsafeAdapter(ClassVisitor cv, ClassLoader loader) {
026: super (cv);
027: }
028:
029: public ClassAdapter create(ClassVisitor visitor, ClassLoader loader) {
030: return new DSOUnsafeAdapter(visitor, loader);
031: }
032:
033: public final void visit(int version, int access, String name,
034: String signature, String super Name, String[] interfaces) {
035: super Name = "sun/misc/Unsafe";
036: super .visit(version, access, name, signature, super Name,
037: interfaces);
038: }
039:
040: public MethodVisitor visitMethod(int access, String name,
041: String desc, String signature, String[] exceptions) {
042: MethodVisitor mv = super .visitMethod(access, name, desc,
043: signature, exceptions);
044:
045: if ("<init>".equals(name)) {
046: mv.visitCode();
047: mv.visitVarInsn(ALOAD, 0);
048: mv.visitMethodInsn(INVOKESPECIAL, "sun/misc/Unsafe",
049: "<init>", "()V");
050: mv.visitInsn(RETURN);
051: mv.visitMaxs(0, 0);
052: mv.visitEnd();
053: return null;
054: }
055:
056: return mv;
057: }
058:
059: public void visitEnd() {
060: MethodVisitor mv = super .visitMethod(ACC_PUBLIC,
061: "compareAndSwapInt", "(Ljava/lang/Object;JII)Z", null,
062: null);
063: addUnsafeWrapperMethodCode(mv, ACC_PUBLIC, "compareAndSwapInt",
064: "(Ljava/lang/Object;JII)Z");
065:
066: mv = super .visitMethod(ACC_PUBLIC, "compareAndSwapLong",
067: "(Ljava/lang/Object;JJJ)Z", null, null);
068: addUnsafeWrapperMethodCode(mv, ACC_PUBLIC,
069: "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z");
070:
071: mv = super
072: .visitMethod(
073: ACC_PUBLIC,
074: "compareAndSwapObject",
075: "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z",
076: null, null);
077: addUnsafeWrapperMethodCode(mv, ACC_PUBLIC,
078: "compareAndSwapObject",
079: "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z");
080:
081: super .visitEnd();
082: }
083:
084: private void addBeginVolatileInstrumentedCode(MethodVisitor mv,
085: Type[] params) {
086: int pos = 0;
087: mv.visitVarInsn(params[0].getOpcode(ILOAD), pos + 1);
088: pos += params[0].getSize();
089: mv.visitVarInsn(params[1].getOpcode(ILOAD), pos + 1);
090: mv.visitIntInsn(BIPUSH, LockLevel.WRITE);
091: mv.visitMethodInsn(INVOKESTATIC,
092: "com/tc/object/bytecode/ManagerUtil",
093: "beginVolatileByOffset", "(Ljava/lang/Object;JI)V");
094: }
095:
096: private void addCommitVolatileInstrumentedCode(MethodVisitor mv,
097: Type[] params) {
098: int pos = 0;
099: mv.visitVarInsn(params[0].getOpcode(ILOAD), pos + 1);
100: pos += params[0].getSize();
101: mv.visitVarInsn(params[1].getOpcode(ILOAD), pos + 1);
102: mv.visitMethodInsn(INVOKESTATIC,
103: "com/tc/object/bytecode/ManagerUtil",
104: "commitVolatileByOffset", "(Ljava/lang/Object;J)V");
105: }
106:
107: private void addCheckedManagedConditionCode(MethodVisitor mv,
108: Type[] params, int objParamIndex, int offsetParamIndex,
109: Label nonSharedLabel, Label sharedLabel) {
110: Label checkPortableFieldLabel = new Label();
111: mv.visitVarInsn(params[objParamIndex].getOpcode(ILOAD),
112: objParamIndex + 1);
113: mv.visitMethodInsn(INVOKESTATIC,
114: "com/tc/object/bytecode/ManagerUtil", "isManaged",
115: "(Ljava/lang/Object;)Z");
116: mv.visitJumpInsn(IFEQ, nonSharedLabel);
117: mv.visitJumpInsn(GOTO, checkPortableFieldLabel);
118: mv.visitLabel(checkPortableFieldLabel);
119: mv.visitVarInsn(params[objParamIndex].getOpcode(ILOAD),
120: objParamIndex + 1);
121: mv.visitVarInsn(params[offsetParamIndex].getOpcode(ILOAD),
122: offsetParamIndex + 1);
123: mv.visitMethodInsn(INVOKESTATIC,
124: "com/tc/object/bytecode/ManagerUtil",
125: "isFieldPortableByOffset", "(Ljava/lang/Object;J)Z");
126: mv.visitJumpInsn(IFEQ, nonSharedLabel);
127: mv.visitJumpInsn(GOTO, sharedLabel);
128: }
129:
130: private int getParameterPosition(Type[] params, int index) {
131: int pos = 0;
132: for (int i = 0; i < index; i++) {
133: pos += params[i].getSize();
134: }
135: return pos;
136: }
137:
138: private void addUnsafeWrapperMethodCode(MethodVisitor mv,
139: int access, String methodName, String description) {
140: mv = new FieldMethodAdapter(access, description, mv);
141:
142: Type[] params = Type.getArgumentTypes(description);
143: Type returnType = Type.getReturnType(description);
144:
145: int newLocalVar1 = ((FieldMethodAdapter) mv)
146: .newLocal(Type.INT_TYPE);
147: int newLocalVar2 = ((FieldMethodAdapter) mv).newLocal(Type
148: .getObjectType("java/lang/Object"));
149: int newLocalVar3 = ((FieldMethodAdapter) mv).newLocal(Type
150: .getObjectType("java/lang/Object"));
151:
152: mv.visitCode();
153:
154: Label l0 = new Label();
155: Label l1 = new Label();
156: mv.visitTryCatchBlock(l0, l1, l1, null);
157: Label l2 = new Label();
158: Label l3 = new Label();
159: mv.visitTryCatchBlock(l2, l3, l1, null);
160: Label l4 = new Label();
161: mv.visitLabel(l4);
162: Label l5 = new Label();
163: Label l6 = new Label();
164: addCheckedManagedConditionCode(mv, params, 0, 1, l6, l5);
165:
166: mv.visitLabel(l6);
167: invokeSuperMethod(mv, methodName, description, params);
168: mv.visitInsn(returnType.getOpcode(IRETURN));
169:
170: mv.visitLabel(l5);
171: mv.visitInsn(ICONST_0);
172: mv.visitVarInsn(ISTORE, newLocalVar1);
173:
174: Label l7 = new Label();
175: mv.visitLabel(l7);
176: addBeginVolatileInstrumentedCode(mv, params);
177:
178: mv.visitLabel(l0);
179: invokeSuperMethod(mv, methodName, description, params);
180: mv.visitVarInsn(ISTORE, newLocalVar1);
181:
182: Label l8 = new Label();
183: mv.visitLabel(l8);
184: mv.visitVarInsn(ILOAD, newLocalVar1);
185: mv.visitJumpInsn(IFEQ, l2);
186:
187: Label l9 = new Label();
188: mv.visitLabel(l9);
189: mv.visitVarInsn(params[0].getOpcode(ILOAD),
190: getParameterPosition(params, 0) + 1);
191: mv.visitVarInsn(params[1].getOpcode(ILOAD),
192: getParameterPosition(params, 1) + 1);
193: ByteCodeUtil.addTypeSpecificParameterLoad(mv, params[3],
194: getParameterPosition(params, 3) + 1);
195: mv.visitMethodInsn(INVOKESTATIC, "com/tc/util/UnsafeUtil",
196: "updateDSOSharedField",
197: "(Ljava/lang/Object;JLjava/lang/Object;)V");
198: mv.visitJumpInsn(GOTO, l2);
199:
200: mv.visitLabel(l1);
201: mv.visitVarInsn(ASTORE, newLocalVar3);
202: Label l10 = new Label();
203: mv.visitJumpInsn(JSR, l10);
204: Label l11 = new Label();
205: mv.visitLabel(l11);
206: mv.visitVarInsn(ALOAD, newLocalVar3);
207: mv.visitInsn(ATHROW);
208: mv.visitLabel(l10);
209: mv.visitVarInsn(ASTORE, newLocalVar2);
210: Label l12 = new Label();
211: mv.visitLabel(l12);
212: addCommitVolatileInstrumentedCode(mv, params);
213: Label l13 = new Label();
214: mv.visitLabel(l13);
215: mv.visitVarInsn(RET, newLocalVar2);
216:
217: mv.visitLabel(l2);
218: mv.visitJumpInsn(JSR, l10);
219: mv.visitLabel(l3);
220: mv.visitVarInsn(ILOAD, newLocalVar1);
221: mv.visitInsn(returnType.getOpcode(IRETURN));
222: Label l14 = new Label();
223: mv.visitLabel(l14);
224: mv.visitMaxs(0, 0);
225: mv.visitEnd();
226: }
227:
228: protected void addCheckWriteAccessInstrumentedCode(
229: MethodVisitor mv, Type[] params, int objParamIndex) {
230: mv.visitVarInsn(params[objParamIndex].getOpcode(ILOAD),
231: objParamIndex + 1);
232: mv.visitMethodInsn(INVOKESTATIC,
233: "com/tc/object/bytecode/ManagerUtil",
234: "checkWriteAccess", "(Ljava/lang/Object;)V");
235: }
236:
237: private void invokeSuperMethod(MethodVisitor mv, String methodName,
238: String description, Type[] params) {
239: ByteCodeUtil.pushThis(mv);
240: int pos = 0;
241: for (int i = 0; i < params.length; i++) {
242: mv.visitVarInsn(params[i].getOpcode(ILOAD), pos + 1);
243: pos += params[i].getSize();
244: }
245: mv.visitMethodInsn(INVOKESPECIAL, "sun/misc/Unsafe",
246: methodName, description);
247: }
248:
249: private class FieldMethodAdapter extends LocalVariablesSorter
250: implements Opcodes {
251: public FieldMethodAdapter(int access, String desc,
252: MethodVisitor mv) {
253: super(access, desc, mv);
254: }
255: }
256:
257: }
|