1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.classfile.editor;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.annotation.*;
26import proguard.classfile.attribute.annotation.visitor.*;
27import proguard.classfile.attribute.preverification.*;
28import proguard.classfile.attribute.preverification.visitor.*;
29import proguard.classfile.attribute.visitor.*;
30import proguard.classfile.constant.*;
31import proguard.classfile.constant.visitor.ConstantVisitor;
32import proguard.classfile.instruction.*;
33import proguard.classfile.instruction.visitor.InstructionVisitor;
34import proguard.classfile.util.SimplifiedVisitor;
35import proguard.classfile.visitor.*;
36
37/**
38 * This ClassVisitor remaps all possible references to constant pool entries
39 * of the classes that it visits, based on a given index map. It is assumed that
40 * the constant pool entries themselves have already been remapped.
41 *
42 * @author Eric Lafortune
43 */
44public class ConstantPoolRemapper
45extends      SimplifiedVisitor
46implements   ClassVisitor,
47             ConstantVisitor,
48             MemberVisitor,
49             AttributeVisitor,
50             InstructionVisitor,
51             InnerClassesInfoVisitor,
52             ExceptionInfoVisitor,
53             StackMapFrameVisitor,
54             VerificationTypeVisitor,
55             LocalVariableInfoVisitor,
56             LocalVariableTypeInfoVisitor,
57             AnnotationVisitor,
58             ElementValueVisitor
59{
60    private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
61
62    private int[] constantIndexMap;
63
64
65    /**
66     * Sets the given mapping of old constant pool entry indexes to their new
67     * indexes.
68     */
69    public void setConstantIndexMap(int[] constantIndexMap)
70    {
71        this.constantIndexMap = constantIndexMap;
72    }
73
74
75    // Implementations for ClassVisitor.
76
77    public void visitProgramClass(ProgramClass programClass)
78    {
79        // Remap the local constant pool references.
80        programClass.u2thisClass  = remapConstantIndex(programClass.u2thisClass);
81        programClass.u2superClass = remapConstantIndex(programClass.u2superClass);
82
83        remapConstantIndexArray(programClass.u2interfaces,
84                                programClass.u2interfacesCount);
85
86        // Remap the references of the contant pool entries themselves.
87        programClass.constantPoolEntriesAccept(this);
88
89        // Remap the references in all fields, methods, and attributes.
90        programClass.fieldsAccept(this);
91        programClass.methodsAccept(this);
92        programClass.attributesAccept(this);
93    }
94
95
96    public void visitLibraryClass(LibraryClass libraryClass)
97    {
98    }
99
100
101    // Implementations for ConstantVisitor.
102
103    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
104    {
105        classConstant.u2nameIndex =
106            remapConstantIndex(classConstant.u2nameIndex);
107    }
108
109
110    public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
111    {
112        // Nothing to do.
113    }
114
115
116    public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant)
117    {
118        fieldrefConstant.u2classIndex =
119            remapConstantIndex(fieldrefConstant.u2classIndex);
120        fieldrefConstant.u2nameAndTypeIndex =
121            remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex);
122    }
123
124
125    public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
126    {
127        // Nothing to do.
128    }
129
130
131    public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
132    {
133        // Nothing to do.
134    }
135
136
137    public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant)
138    {
139        interfaceMethodrefConstant.u2classIndex =
140            remapConstantIndex(interfaceMethodrefConstant.u2classIndex);
141        interfaceMethodrefConstant.u2nameAndTypeIndex =
142            remapConstantIndex(interfaceMethodrefConstant.u2nameAndTypeIndex);
143    }
144
145
146    public void visitLongConstant(Clazz clazz, LongConstant longConstant)
147    {
148        // Nothing to do.
149    }
150
151
152    public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant)
153    {
154        methodrefConstant.u2classIndex =
155            remapConstantIndex(methodrefConstant.u2classIndex);
156        methodrefConstant.u2nameAndTypeIndex =
157            remapConstantIndex(methodrefConstant.u2nameAndTypeIndex);
158    }
159
160
161    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
162    {
163        nameAndTypeConstant.u2nameIndex =
164            remapConstantIndex(nameAndTypeConstant.u2nameIndex);
165        nameAndTypeConstant.u2descriptorIndex =
166            remapConstantIndex(nameAndTypeConstant.u2descriptorIndex);
167    }
168
169
170    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
171    {
172        stringConstant.u2stringIndex =
173            remapConstantIndex(stringConstant.u2stringIndex);
174    }
175
176
177    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
178    {
179        // Nothing to do.
180    }
181
182
183    // Implementations for MemberVisitor.
184
185    public void visitProgramField(ProgramClass programClass, ProgramField programField)
186    {
187        visitMember(programClass, programField);
188    }
189
190
191    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
192    {
193        visitMember(programClass, programMethod);
194    }
195
196
197    private void visitMember(ProgramClass programClass, ProgramMember programMember)
198    {
199        // Remap the local constant pool references.
200        programMember.u2nameIndex =
201            remapConstantIndex(programMember.u2nameIndex);
202        programMember.u2descriptorIndex =
203            remapConstantIndex(programMember.u2descriptorIndex);
204
205        // Remap the constant pool references of the remaining attributes.
206        programMember.attributesAccept(programClass, this);
207    }
208
209
210    public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
211    {
212        // Library classes are left unchanged.
213    }
214
215
216    public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
217    {
218        // Library classes are left unchanged.
219    }
220
221
222    // Implementations for AttributeVisitor.
223
224    public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
225    {
226        unknownAttribute.u2attributeNameIndex =
227            remapConstantIndex(unknownAttribute.u2attributeNameIndex);
228
229        // There's not much else we can do with unknown attributes.
230    }
231
232
233    public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
234    {
235        sourceFileAttribute.u2attributeNameIndex =
236            remapConstantIndex(sourceFileAttribute.u2attributeNameIndex);
237        sourceFileAttribute.u2sourceFileIndex =
238            remapConstantIndex(sourceFileAttribute.u2sourceFileIndex);
239    }
240
241
242    public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
243    {
244        sourceDirAttribute.u2attributeNameIndex =
245            remapConstantIndex(sourceDirAttribute.u2attributeNameIndex);
246        sourceDirAttribute.u2sourceDirIndex       =
247            remapConstantIndex(sourceDirAttribute.u2sourceDirIndex);
248    }
249
250
251    public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
252    {
253        innerClassesAttribute.u2attributeNameIndex =
254            remapConstantIndex(innerClassesAttribute.u2attributeNameIndex);
255
256        // Remap the constant pool references of the inner classes.
257        innerClassesAttribute.innerClassEntriesAccept(clazz, this);
258    }
259
260
261    public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
262    {
263        enclosingMethodAttribute.u2attributeNameIndex =
264            remapConstantIndex(enclosingMethodAttribute.u2attributeNameIndex);
265        enclosingMethodAttribute.u2classIndex =
266            remapConstantIndex(enclosingMethodAttribute.u2classIndex);
267        enclosingMethodAttribute.u2nameAndTypeIndex =
268            remapConstantIndex(enclosingMethodAttribute.u2nameAndTypeIndex);
269    }
270
271
272    public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
273    {
274        deprecatedAttribute.u2attributeNameIndex =
275            remapConstantIndex(deprecatedAttribute.u2attributeNameIndex);
276    }
277
278
279    public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
280    {
281        syntheticAttribute.u2attributeNameIndex =
282            remapConstantIndex(syntheticAttribute.u2attributeNameIndex);
283    }
284
285
286    public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
287    {
288        signatureAttribute.u2attributeNameIndex =
289            remapConstantIndex(signatureAttribute.u2attributeNameIndex);
290        signatureAttribute.u2signatureIndex       =
291            remapConstantIndex(signatureAttribute.u2signatureIndex);
292    }
293
294
295    public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
296    {
297        constantValueAttribute.u2attributeNameIndex =
298            remapConstantIndex(constantValueAttribute.u2attributeNameIndex);
299        constantValueAttribute.u2constantValueIndex =
300            remapConstantIndex(constantValueAttribute.u2constantValueIndex);
301    }
302
303
304    public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
305    {
306        exceptionsAttribute.u2attributeNameIndex =
307            remapConstantIndex(exceptionsAttribute.u2attributeNameIndex);
308
309        // Remap the constant pool references of the exceptions.
310        remapConstantIndexArray(exceptionsAttribute.u2exceptionIndexTable,
311                                exceptionsAttribute.u2exceptionIndexTableLength);
312    }
313
314
315    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
316    {
317        codeAttribute.u2attributeNameIndex =
318            remapConstantIndex(codeAttribute.u2attributeNameIndex);
319
320        // Initially, the code attribute editor doesn't contain any changes.
321        codeAttributeEditor.reset(codeAttribute.u4codeLength);
322
323        // Remap the constant pool references of the instructions.
324        codeAttribute.instructionsAccept(clazz, method, this);
325
326        // Apply the code atribute editor. It will only contain any changes if
327        // the code length is changing at any point.
328        codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
329
330        // Remap the constant pool references of the exceptions and attributes.
331        codeAttribute.exceptionsAccept(clazz, method, this);
332        codeAttribute.attributesAccept(clazz, method, this);
333    }
334
335
336    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
337    {
338        stackMapAttribute.u2attributeNameIndex =
339            remapConstantIndex(stackMapAttribute.u2attributeNameIndex);
340
341        // Remap the constant pool references of the stack map frames.
342        stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
343    }
344
345
346    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
347    {
348        stackMapTableAttribute.u2attributeNameIndex =
349            remapConstantIndex(stackMapTableAttribute.u2attributeNameIndex);
350
351        // Remap the constant pool references of the stack map frames.
352        stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this);
353    }
354
355
356    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
357    {
358        lineNumberTableAttribute.u2attributeNameIndex =
359            remapConstantIndex(lineNumberTableAttribute.u2attributeNameIndex);
360    }
361
362
363    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
364    {
365        localVariableTableAttribute.u2attributeNameIndex =
366            remapConstantIndex(localVariableTableAttribute.u2attributeNameIndex);
367
368        // Remap the constant pool references of the local variables.
369        localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
370    }
371
372
373    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
374    {
375        localVariableTypeTableAttribute.u2attributeNameIndex =
376            remapConstantIndex(localVariableTypeTableAttribute.u2attributeNameIndex);
377
378        // Remap the constant pool references of the local variables.
379        localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this);
380    }
381
382
383    public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
384    {
385        annotationsAttribute.u2attributeNameIndex =
386            remapConstantIndex(annotationsAttribute.u2attributeNameIndex);
387
388        // Remap the constant pool references of the annotations.
389        annotationsAttribute.annotationsAccept(clazz, this);
390    }
391
392
393    public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
394    {
395        parameterAnnotationsAttribute.u2attributeNameIndex =
396            remapConstantIndex(parameterAnnotationsAttribute.u2attributeNameIndex);
397
398        // Remap the constant pool references of the annotations.
399        parameterAnnotationsAttribute.annotationsAccept(clazz, method, this);
400    }
401
402
403    public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
404    {
405        annotationDefaultAttribute.u2attributeNameIndex =
406            remapConstantIndex(annotationDefaultAttribute.u2attributeNameIndex);
407
408        // Remap the constant pool references of the annotations.
409        annotationDefaultAttribute.defaultValueAccept(clazz, this);
410    }
411
412
413    // Implementations for InnerClassesInfoVisitor.
414
415    public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
416    {
417        if (innerClassesInfo.u2innerClassIndex != 0)
418        {
419            innerClassesInfo.u2innerClassIndex =
420                remapConstantIndex(innerClassesInfo.u2innerClassIndex);
421        }
422
423        if (innerClassesInfo.u2outerClassIndex != 0)
424        {
425            innerClassesInfo.u2outerClassIndex =
426                remapConstantIndex(innerClassesInfo.u2outerClassIndex);
427        }
428
429        if (innerClassesInfo.u2innerNameIndex != 0)
430        {
431            innerClassesInfo.u2innerNameIndex =
432                remapConstantIndex(innerClassesInfo.u2innerNameIndex);
433        }
434    }
435
436
437    // Implementations for ExceptionInfoVisitor.
438
439    public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
440    {
441        if (exceptionInfo.u2catchType != 0)
442        {
443            exceptionInfo.u2catchType =
444                remapConstantIndex(exceptionInfo.u2catchType);
445        }
446    }
447
448
449    // Implementations for InstructionVisitor.
450
451    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
452
453
454    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
455    {
456        // Is the new constant pool index different from the original one?
457        int newConstantIndex = remapConstantIndex(constantInstruction.constantIndex);
458        if (newConstantIndex != constantInstruction.constantIndex)
459        {
460            // Replace the instruction.
461            Instruction replacementInstruction =
462                new ConstantInstruction(constantInstruction.opcode,
463                                        newConstantIndex,
464                                        constantInstruction.constant).shrink();
465
466            codeAttributeEditor.replaceInstruction(offset, replacementInstruction);
467        }
468    }
469
470
471    // Implementations for StackMapFrameVisitor.
472
473    public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {}
474
475
476    public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
477    {
478        // Remap the constant pool references of the verification types.
479        sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this);
480    }
481
482
483    public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
484    {
485        // Remap the constant pool references of the verification types.
486        moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this);
487    }
488
489
490    public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
491    {
492        // Remap the constant pool references of the verification types.
493        fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this);
494        fullFrame.stackAccept(clazz, method, codeAttribute, offset, this);
495    }
496
497
498    // Implementations for VerificationTypeVisitor.
499
500    public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {}
501
502
503    public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType)
504    {
505        objectType.u2classIndex =
506            remapConstantIndex(objectType.u2classIndex);
507    }
508
509
510    // Implementations for LocalVariableInfoVisitor.
511
512    public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
513    {
514        localVariableInfo.u2nameIndex =
515            remapConstantIndex(localVariableInfo.u2nameIndex);
516        localVariableInfo.u2descriptorIndex =
517            remapConstantIndex(localVariableInfo.u2descriptorIndex);
518    }
519
520
521    // Implementations for LocalVariableTypeInfoVisitor.
522
523    public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
524    {
525        localVariableTypeInfo.u2nameIndex =
526            remapConstantIndex(localVariableTypeInfo.u2nameIndex);
527        localVariableTypeInfo.u2signatureIndex       =
528            remapConstantIndex(localVariableTypeInfo.u2signatureIndex);
529    }
530
531
532    // Implementations for AnnotationVisitor.
533
534    public void visitAnnotation(Clazz clazz, Annotation annotation)
535    {
536        annotation.u2typeIndex =
537            remapConstantIndex(annotation.u2typeIndex);
538
539        // Remap the constant pool references of the element values.
540        annotation.elementValuesAccept(clazz, this);
541    }
542
543
544    // Implementations for ElementValueVisitor.
545
546    public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
547    {
548        constantElementValue.u2elementNameIndex =
549            remapConstantIndex(constantElementValue.u2elementNameIndex);
550        constantElementValue.u2constantValueIndex =
551            remapConstantIndex(constantElementValue.u2constantValueIndex);
552    }
553
554
555    public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
556    {
557        enumConstantElementValue.u2elementNameIndex =
558            remapConstantIndex(enumConstantElementValue.u2elementNameIndex);
559        enumConstantElementValue.u2typeNameIndex =
560            remapConstantIndex(enumConstantElementValue.u2typeNameIndex);
561        enumConstantElementValue.u2constantNameIndex =
562            remapConstantIndex(enumConstantElementValue.u2constantNameIndex);
563    }
564
565
566    public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
567    {
568        classElementValue.u2elementNameIndex =
569            remapConstantIndex(classElementValue.u2elementNameIndex);
570        classElementValue.u2classInfoIndex       =
571            remapConstantIndex(classElementValue.u2classInfoIndex);
572    }
573
574
575    public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
576    {
577        annotationElementValue.u2elementNameIndex =
578            remapConstantIndex(annotationElementValue.u2elementNameIndex);
579
580        // Remap the constant pool references of the annotation.
581        annotationElementValue.annotationAccept(clazz, this);
582    }
583
584
585    public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
586    {
587        arrayElementValue.u2elementNameIndex =
588            remapConstantIndex(arrayElementValue.u2elementNameIndex);
589
590        // Remap the constant pool references of the element values.
591        arrayElementValue.elementValuesAccept(clazz, annotation, this);
592    }
593
594
595    // Small utility methods.
596
597    /**
598     * Remaps all constant pool indices in the given array.
599     */
600    private void remapConstantIndexArray(int[] array, int length)
601    {
602        for (int index = 0; index < length; index++)
603        {
604            array[index] = remapConstantIndex(array[index]);
605        }
606    }
607
608
609    /**
610     * Returns the new constant pool index of the entry at the
611     * given index.
612     */
613    private int remapConstantIndex(int constantIndex)
614    {
615        return constantIndexMap[constantIndex];
616    }
617}
618