ClassTranslator.java revision 3822:d8766c39123a
1/*
2 * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.classfile;
27
28import java.util.Map;
29
30import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
31import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
32import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
33import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
34import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info;
35import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info;
36import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info;
37import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info;
38import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info;
39import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodType_info;
40import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info;
41import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info;
42import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info;
43import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info;
44import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info;
45import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
46import com.sun.tools.classfile.ConstantPool.CPInfo;
47
48/**
49 * Rewrites a class file using a map of translations.
50 *
51 *  <p><b>This is NOT part of any supported API.
52 *  If you write code that depends on this, you do so at your own risk.
53 *  This code and its internal interfaces are subject to change or
54 *  deletion without notice.</b>
55 */
56public class ClassTranslator
57        implements ConstantPool.Visitor<ConstantPool.CPInfo,Map<Object,Object>> {
58    /**
59     * Create a new ClassFile from {@code cf}, such that for all entries
60     * {@code k&nbsp;-\&gt;&nbsp;v} in {@code translations},
61     * each occurrence of {@code k} in {@code cf} will be replaced by {@code v}.
62     * in
63     * @param cf the class file to be processed
64     * @param translations the set of translations to be applied
65     * @return a copy of {@code} with the values in {@code translations} substituted
66     */
67    public ClassFile translate(ClassFile cf, Map<Object,Object> translations) {
68        ClassFile cf2 = (ClassFile) translations.get(cf);
69        if (cf2 == null) {
70            ConstantPool constant_pool2 = translate(cf.constant_pool, translations);
71            Field[] fields2 = translate(cf.fields, cf.constant_pool, translations);
72            Method[] methods2 = translateMethods(cf.methods, cf.constant_pool, translations);
73            Attributes attributes2 = translateAttributes(cf.attributes, cf.constant_pool,
74                    translations);
75
76            if (constant_pool2 == cf.constant_pool &&
77                    fields2 == cf.fields &&
78                    methods2 == cf.methods &&
79                    attributes2 == cf.attributes)
80                cf2 = cf;
81            else
82                cf2 = new ClassFile(
83                        cf.magic,
84                        cf.minor_version,
85                        cf.major_version,
86                        constant_pool2,
87                        cf.access_flags,
88                        cf.this_class,
89                        cf.super_class,
90                        cf.interfaces,
91                        fields2,
92                        methods2,
93                        attributes2);
94            translations.put(cf, cf2);
95        }
96        return cf2;
97    }
98
99    ConstantPool translate(ConstantPool cp, Map<Object,Object> translations) {
100        ConstantPool cp2 = (ConstantPool) translations.get(cp);
101        if (cp2 == null) {
102            ConstantPool.CPInfo[] pool2 = new ConstantPool.CPInfo[cp.size()];
103            boolean eq = true;
104            for (int i = 0; i < cp.size(); ) {
105                ConstantPool.CPInfo cpInfo;
106                try {
107                    cpInfo = cp.get(i);
108                } catch (ConstantPool.InvalidIndex e) {
109                    throw new IllegalStateException(e);
110                }
111                ConstantPool.CPInfo cpInfo2 = translate(cpInfo, translations);
112                eq &= (cpInfo == cpInfo2);
113                pool2[i] = cpInfo2;
114                if (cpInfo.getTag() != cpInfo2.getTag())
115                    throw new IllegalStateException();
116                i += cpInfo.size();
117            }
118
119            if (eq)
120                cp2 = cp;
121            else
122                cp2 = new ConstantPool(pool2);
123
124            translations.put(cp, cp2);
125        }
126        return cp2;
127    }
128
129    ConstantPool.CPInfo translate(ConstantPool.CPInfo cpInfo, Map<Object,Object> translations) {
130        ConstantPool.CPInfo cpInfo2 = (ConstantPool.CPInfo) translations.get(cpInfo);
131        if (cpInfo2 == null) {
132            cpInfo2 = cpInfo.accept(this, translations);
133            translations.put(cpInfo, cpInfo2);
134        }
135        return cpInfo2;
136    }
137
138    Field[] translate(Field[] fields, ConstantPool constant_pool, Map<Object,Object> translations) {
139        Field[] fields2 = (Field[]) translations.get(fields);
140        if (fields2 == null) {
141            fields2 = new Field[fields.length];
142            for (int i = 0; i < fields.length; i++)
143                fields2[i] = translate(fields[i], constant_pool, translations);
144            if (equal(fields, fields2))
145                fields2 = fields;
146            translations.put(fields, fields2);
147        }
148        return fields2;
149    }
150
151    Field translate(Field field, ConstantPool constant_pool, Map<Object,Object> translations) {
152        Field field2 = (Field) translations.get(field);
153        if (field2 == null) {
154            Attributes attributes2 = translateAttributes(field.attributes, constant_pool,
155                    translations);
156
157            if (attributes2 == field.attributes)
158                field2 = field;
159            else
160                field2 = new Field(
161                        field.access_flags,
162                        field.name_index,
163                        field.descriptor,
164                        attributes2);
165            translations.put(field, field2);
166        }
167        return field2;
168    }
169
170    Method[] translateMethods(Method[] methods, ConstantPool constant_pool, Map<Object,Object> translations) {
171        Method[] methods2 = (Method[]) translations.get(methods);
172        if (methods2 == null) {
173            methods2 = new Method[methods.length];
174            for (int i = 0; i < methods.length; i++)
175                methods2[i] = translate(methods[i], constant_pool, translations);
176            if (equal(methods, methods2))
177                methods2 = methods;
178            translations.put(methods, methods2);
179        }
180        return methods2;
181    }
182
183    Method translate(Method method, ConstantPool constant_pool, Map<Object,Object> translations) {
184        Method method2 = (Method) translations.get(method);
185        if (method2 == null) {
186            Attributes attributes2 = translateAttributes(method.attributes, constant_pool,
187                    translations);
188
189            if (attributes2 == method.attributes)
190                method2 = method;
191            else
192                method2 = new Method(
193                        method.access_flags,
194                        method.name_index,
195                        method.descriptor,
196                        attributes2);
197            translations.put(method, method2);
198        }
199        return method2;
200    }
201
202    Attributes translateAttributes(Attributes attributes,
203            ConstantPool constant_pool, Map<Object,Object> translations) {
204        Attributes attributes2 = (Attributes) translations.get(attributes);
205        if (attributes2 == null) {
206            Attribute[] attrArray2 = new Attribute[attributes.size()];
207            ConstantPool constant_pool2 = translate(constant_pool, translations);
208            boolean attrsEqual = true;
209            for (int i = 0; i < attributes.size(); i++) {
210                Attribute attr = attributes.get(i);
211                Attribute attr2 = translate(attr, translations);
212                if (attr2 != attr)
213                    attrsEqual = false;
214                attrArray2[i] = attr2;
215            }
216            if ((constant_pool2 == constant_pool) && attrsEqual)
217                attributes2 = attributes;
218            else
219                attributes2 = new Attributes(constant_pool2, attrArray2);
220            translations.put(attributes, attributes2);
221        }
222        return attributes2;
223    }
224
225    Attribute translate(Attribute attribute, Map<Object,Object> translations) {
226        Attribute attribute2 = (Attribute) translations.get(attribute);
227        if (attribute2 == null) {
228            attribute2 = attribute; // don't support translation within attributes yet
229                                    // (what about Code attribute)
230            translations.put(attribute, attribute2);
231        }
232        return attribute2;
233    }
234
235    private static <T> boolean equal(T[] a1, T[] a2) {
236        if (a1 == null || a2 == null)
237            return (a1 == a2);
238        if (a1.length != a2.length)
239            return false;
240        for (int i = 0; i < a1.length; i++) {
241            if (a1[i] != a2[i])
242                return false;
243        }
244        return true;
245    }
246
247    @Override
248    public CPInfo visitClass(CONSTANT_Class_info info, Map<Object, Object> translations) {
249        CONSTANT_Class_info info2 = (CONSTANT_Class_info) translations.get(info);
250        if (info2 == null) {
251            ConstantPool cp2 = translate(info.cp, translations);
252            if (cp2 == info.cp)
253                info2 = info;
254            else
255                info2 = new CONSTANT_Class_info(cp2, info.name_index);
256            translations.put(info, info2);
257        }
258        return info;
259    }
260
261    @Override
262    public CPInfo visitDouble(CONSTANT_Double_info info, Map<Object, Object> translations) {
263        CONSTANT_Double_info info2 = (CONSTANT_Double_info) translations.get(info);
264        if (info2 == null) {
265            info2 = info;
266            translations.put(info, info2);
267        }
268        return info;
269    }
270
271    @Override
272    public CPInfo visitFieldref(CONSTANT_Fieldref_info info, Map<Object, Object> translations) {
273        CONSTANT_Fieldref_info info2 = (CONSTANT_Fieldref_info) translations.get(info);
274        if (info2 == null) {
275            ConstantPool cp2 = translate(info.cp, translations);
276            if (cp2 == info.cp)
277                info2 = info;
278            else
279                info2 = new CONSTANT_Fieldref_info(cp2, info.class_index, info.name_and_type_index);
280            translations.put(info, info2);
281        }
282        return info;
283    }
284
285    @Override
286    public CPInfo visitFloat(CONSTANT_Float_info info, Map<Object, Object> translations) {
287        CONSTANT_Float_info info2 = (CONSTANT_Float_info) translations.get(info);
288        if (info2 == null) {
289            info2 = info;
290            translations.put(info, info2);
291        }
292        return info;
293    }
294
295    @Override
296    public CPInfo visitInteger(CONSTANT_Integer_info info, Map<Object, Object> translations) {
297        CONSTANT_Integer_info info2 = (CONSTANT_Integer_info) translations.get(info);
298        if (info2 == null) {
299            info2 = info;
300            translations.put(info, info2);
301        }
302        return info;
303    }
304
305    @Override
306    public CPInfo visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Map<Object, Object> translations) {
307        CONSTANT_InterfaceMethodref_info info2 = (CONSTANT_InterfaceMethodref_info) translations.get(info);
308        if (info2 == null) {
309            ConstantPool cp2 = translate(info.cp, translations);
310            if (cp2 == info.cp)
311                info2 = info;
312            else
313                info2 = new CONSTANT_InterfaceMethodref_info(cp2, info.class_index, info.name_and_type_index);
314            translations.put(info, info2);
315        }
316        return info;
317    }
318
319    @Override
320    public CPInfo visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Map<Object, Object> translations) {
321        CONSTANT_InvokeDynamic_info info2 = (CONSTANT_InvokeDynamic_info) translations.get(info);
322        if (info2 == null) {
323            ConstantPool cp2 = translate(info.cp, translations);
324            if (cp2 == info.cp) {
325                info2 = info;
326            } else {
327                info2 = new CONSTANT_InvokeDynamic_info(cp2, info.bootstrap_method_attr_index, info.name_and_type_index);
328            }
329            translations.put(info, info2);
330        }
331        return info;
332    }
333
334    @Override
335    public CPInfo visitLong(CONSTANT_Long_info info, Map<Object, Object> translations) {
336        CONSTANT_Long_info info2 = (CONSTANT_Long_info) translations.get(info);
337        if (info2 == null) {
338            info2 = info;
339            translations.put(info, info2);
340        }
341        return info;
342    }
343
344    @Override
345    public CPInfo visitMethodref(CONSTANT_Methodref_info info, Map<Object, Object> translations) {
346        CONSTANT_Methodref_info info2 = (CONSTANT_Methodref_info) translations.get(info);
347        if (info2 == null) {
348            ConstantPool cp2 = translate(info.cp, translations);
349            if (cp2 == info.cp)
350                info2 = info;
351            else
352                info2 = new CONSTANT_Methodref_info(cp2, info.class_index, info.name_and_type_index);
353            translations.put(info, info2);
354        }
355        return info;
356    }
357
358    @Override
359    public CPInfo visitMethodHandle(CONSTANT_MethodHandle_info info, Map<Object, Object> translations) {
360        CONSTANT_MethodHandle_info info2 = (CONSTANT_MethodHandle_info) translations.get(info);
361        if (info2 == null) {
362            ConstantPool cp2 = translate(info.cp, translations);
363            if (cp2 == info.cp) {
364                info2 = info;
365            } else {
366                info2 = new CONSTANT_MethodHandle_info(cp2, info.reference_kind, info.reference_index);
367            }
368            translations.put(info, info2);
369        }
370        return info;
371    }
372
373    @Override
374    public CPInfo visitMethodType(CONSTANT_MethodType_info info, Map<Object, Object> translations) {
375        CONSTANT_MethodType_info info2 = (CONSTANT_MethodType_info) translations.get(info);
376        if (info2 == null) {
377            ConstantPool cp2 = translate(info.cp, translations);
378            if (cp2 == info.cp) {
379                info2 = info;
380            } else {
381                info2 = new CONSTANT_MethodType_info(cp2, info.descriptor_index);
382            }
383            translations.put(info, info2);
384        }
385        return info;
386    }
387
388    @Override
389    public CPInfo visitModule(CONSTANT_Module_info info, Map<Object, Object> translations) {
390        CONSTANT_Module_info info2 = (CONSTANT_Module_info) translations.get(info);
391        if (info2 == null) {
392            ConstantPool cp2 = translate(info.cp, translations);
393            if (cp2 == info.cp)
394                info2 = info;
395            else
396                info2 = new CONSTANT_Module_info(cp2, info.name_index);
397            translations.put(info, info2);
398        }
399        return info;
400    }
401
402    @Override
403    public CPInfo visitNameAndType(CONSTANT_NameAndType_info info, Map<Object, Object> translations) {
404        CONSTANT_NameAndType_info info2 = (CONSTANT_NameAndType_info) translations.get(info);
405        if (info2 == null) {
406            ConstantPool cp2 = translate(info.cp, translations);
407            if (cp2 == info.cp)
408                info2 = info;
409            else
410                info2 = new CONSTANT_NameAndType_info(cp2, info.name_index, info.type_index);
411            translations.put(info, info2);
412        }
413        return info;
414    }
415
416    @Override
417    public CPInfo visitPackage(CONSTANT_Package_info info, Map<Object, Object> translations) {
418        CONSTANT_Package_info info2 = (CONSTANT_Package_info) translations.get(info);
419        if (info2 == null) {
420            ConstantPool cp2 = translate(info.cp, translations);
421            if (cp2 == info.cp)
422                info2 = info;
423            else
424                info2 = new CONSTANT_Package_info(cp2, info.name_index);
425            translations.put(info, info2);
426        }
427        return info;
428    }
429
430    @Override
431    public CPInfo visitString(CONSTANT_String_info info, Map<Object, Object> translations) {
432        CONSTANT_String_info info2 = (CONSTANT_String_info) translations.get(info);
433        if (info2 == null) {
434            ConstantPool cp2 = translate(info.cp, translations);
435            if (cp2 == info.cp)
436                info2 = info;
437            else
438                info2 = new CONSTANT_String_info(cp2, info.string_index);
439            translations.put(info, info2);
440        }
441        return info;
442    }
443
444    @Override
445    public CPInfo visitUtf8(CONSTANT_Utf8_info info, Map<Object, Object> translations) {
446        CONSTANT_Utf8_info info2 = (CONSTANT_Utf8_info) translations.get(info);
447        if (info2 == null) {
448            info2 = info;
449            translations.put(info, info2);
450        }
451        return info;
452    }
453
454}
455