1 /* |
1 /* |
2 * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
29 import java.util.LinkedHashMap; |
29 import java.util.LinkedHashMap; |
30 import java.util.Map; |
30 import java.util.Map; |
31 import java.util.Set; |
31 import java.util.Set; |
32 import java.util.HashSet; |
32 import java.util.HashSet; |
33 |
33 |
|
34 import javax.lang.model.type.TypeKind; |
34 import javax.tools.JavaFileManager; |
35 import javax.tools.JavaFileManager; |
35 import javax.tools.FileObject; |
36 import javax.tools.FileObject; |
36 import javax.tools.JavaFileObject; |
37 import javax.tools.JavaFileObject; |
37 |
38 |
38 import com.sun.tools.javac.code.*; |
39 import com.sun.tools.javac.code.*; |
39 import com.sun.tools.javac.code.Attribute.RetentionPolicy; |
40 import com.sun.tools.javac.code.Attribute.RetentionPolicy; |
|
41 import com.sun.tools.javac.code.Attribute.TypeCompound; |
40 import com.sun.tools.javac.code.Symbol.*; |
42 import com.sun.tools.javac.code.Symbol.*; |
41 import com.sun.tools.javac.code.Type.*; |
43 import com.sun.tools.javac.code.Type.*; |
42 import com.sun.tools.javac.code.Types.UniqueType; |
44 import com.sun.tools.javac.code.Types.UniqueType; |
43 import com.sun.tools.javac.file.BaseFileObject; |
45 import com.sun.tools.javac.file.BaseFileObject; |
44 import com.sun.tools.javac.jvm.Pool.DynamicMethod; |
46 import com.sun.tools.javac.jvm.Pool.DynamicMethod; |
45 import com.sun.tools.javac.jvm.Pool.Method; |
47 import com.sun.tools.javac.jvm.Pool.Method; |
46 import com.sun.tools.javac.jvm.Pool.MethodHandle; |
48 import com.sun.tools.javac.jvm.Pool.MethodHandle; |
47 import com.sun.tools.javac.jvm.Pool.Variable; |
49 import com.sun.tools.javac.jvm.Pool.Variable; |
48 import com.sun.tools.javac.util.*; |
50 import com.sun.tools.javac.util.*; |
49 |
51 |
50 import static com.sun.tools.javac.code.BoundKind.*; |
|
51 import static com.sun.tools.javac.code.Flags.*; |
52 import static com.sun.tools.javac.code.Flags.*; |
52 import static com.sun.tools.javac.code.Kinds.*; |
53 import static com.sun.tools.javac.code.Kinds.*; |
53 import static com.sun.tools.javac.code.TypeTag.*; |
54 import static com.sun.tools.javac.code.TypeTag.*; |
54 import static com.sun.tools.javac.jvm.UninitializedType.*; |
55 import static com.sun.tools.javac.jvm.UninitializedType.*; |
55 import static com.sun.tools.javac.main.Option.*; |
56 import static com.sun.tools.javac.main.Option.*; |
66 */ |
67 */ |
67 public class ClassWriter extends ClassFile { |
68 public class ClassWriter extends ClassFile { |
68 protected static final Context.Key<ClassWriter> classWriterKey = |
69 protected static final Context.Key<ClassWriter> classWriterKey = |
69 new Context.Key<ClassWriter>(); |
70 new Context.Key<ClassWriter>(); |
70 |
71 |
71 private final Symtab syms; |
|
72 |
|
73 private final Options options; |
72 private final Options options; |
74 |
73 |
75 /** Switch: verbose output. |
74 /** Switch: verbose output. |
76 */ |
75 */ |
77 private boolean verbose; |
76 private boolean verbose; |
78 |
77 |
79 /** Switch: scramble private names. |
78 /** Switch: scramble private field names. |
80 */ |
79 */ |
81 private boolean scramble; |
80 private boolean scramble; |
82 |
81 |
83 /** Switch: scramble private names. |
82 /** Switch: scramble all field names. |
84 */ |
83 */ |
85 private boolean scrambleAll; |
84 private boolean scrambleAll; |
86 |
85 |
87 /** Switch: retrofit mode. |
86 /** Switch: retrofit mode. |
88 */ |
87 */ |
112 |
111 |
113 /** Type utilities. */ |
112 /** Type utilities. */ |
114 private Types types; |
113 private Types types; |
115 |
114 |
116 /** The initial sizes of the data and constant pool buffers. |
115 /** The initial sizes of the data and constant pool buffers. |
117 * sizes are increased when buffers get full. |
116 * Sizes are increased when buffers get full. |
118 */ |
117 */ |
119 static final int DATA_BUF_SIZE = 0x0fff0; |
118 static final int DATA_BUF_SIZE = 0x0fff0; |
120 static final int POOL_BUF_SIZE = 0x1fff0; |
119 static final int POOL_BUF_SIZE = 0x1fff0; |
121 |
120 |
122 /** An output buffer for member info. |
121 /** An output buffer for member info. |
179 protected ClassWriter(Context context) { |
178 protected ClassWriter(Context context) { |
180 context.put(classWriterKey, this); |
179 context.put(classWriterKey, this); |
181 |
180 |
182 log = Log.instance(context); |
181 log = Log.instance(context); |
183 names = Names.instance(context); |
182 names = Names.instance(context); |
184 syms = Symtab.instance(context); |
|
185 options = Options.instance(context); |
183 options = Options.instance(context); |
186 target = Target.instance(context); |
184 target = Target.instance(context); |
187 source = Source.instance(context); |
185 source = Source.instance(context); |
188 types = Types.instance(context); |
186 types = Types.instance(context); |
189 fileManager = context.get(JavaFileManager.class); |
187 fileManager = context.get(JavaFileManager.class); |
836 attrCount++; |
837 attrCount++; |
837 } |
838 } |
838 return attrCount; |
839 return attrCount; |
839 } |
840 } |
840 |
841 |
|
842 int writeTypeAnnotations(List<Attribute.TypeCompound> typeAnnos) { |
|
843 if (typeAnnos.isEmpty()) return 0; |
|
844 |
|
845 ListBuffer<Attribute.TypeCompound> visibles = ListBuffer.lb(); |
|
846 ListBuffer<Attribute.TypeCompound> invisibles = ListBuffer.lb(); |
|
847 |
|
848 for (Attribute.TypeCompound tc : typeAnnos) { |
|
849 if (tc.position == null || tc.position.type == TargetType.UNKNOWN) { |
|
850 boolean found = false; |
|
851 // TODO: the position for the container annotation of a |
|
852 // repeating type annotation has to be set. |
|
853 // This cannot be done when the container is created, because |
|
854 // then the position is not determined yet. |
|
855 // How can we link these pieces better together? |
|
856 if (tc.values.size() == 1) { |
|
857 Pair<MethodSymbol, Attribute> val = tc.values.get(0); |
|
858 if (val.fst.getSimpleName().contentEquals("value") && |
|
859 val.snd instanceof Attribute.Array) { |
|
860 Attribute.Array arr = (Attribute.Array) val.snd; |
|
861 if (arr.values.length != 0 && |
|
862 arr.values[0] instanceof Attribute.TypeCompound) { |
|
863 TypeCompound atycomp = (Attribute.TypeCompound) arr.values[0]; |
|
864 if (atycomp.position.type != TargetType.UNKNOWN) { |
|
865 tc.position = atycomp.position; |
|
866 found = true; |
|
867 } |
|
868 } |
|
869 } |
|
870 } |
|
871 if (!found) { |
|
872 // This happens for nested types like @A Outer. @B Inner. |
|
873 // For method parameters we get the annotation twice! Once with |
|
874 // a valid position, once unknown. |
|
875 // TODO: find a cleaner solution. |
|
876 // System.err.println("ClassWriter: Position UNKNOWN in type annotation: " + tc); |
|
877 continue; |
|
878 } |
|
879 } |
|
880 if (!tc.position.emitToClassfile()) |
|
881 continue; |
|
882 switch (types.getRetention(tc)) { |
|
883 case SOURCE: break; |
|
884 case CLASS: invisibles.append(tc); break; |
|
885 case RUNTIME: visibles.append(tc); break; |
|
886 default: ;// /* fail soft */ throw new AssertionError(vis); |
|
887 } |
|
888 } |
|
889 |
|
890 int attrCount = 0; |
|
891 if (visibles.length() != 0) { |
|
892 int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations); |
|
893 databuf.appendChar(visibles.length()); |
|
894 for (Attribute.TypeCompound p : visibles) |
|
895 writeTypeAnnotation(p); |
|
896 endAttr(attrIndex); |
|
897 attrCount++; |
|
898 } |
|
899 |
|
900 if (invisibles.length() != 0) { |
|
901 int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations); |
|
902 databuf.appendChar(invisibles.length()); |
|
903 for (Attribute.TypeCompound p : invisibles) |
|
904 writeTypeAnnotation(p); |
|
905 endAttr(attrIndex); |
|
906 attrCount++; |
|
907 } |
|
908 |
|
909 return attrCount; |
|
910 } |
|
911 |
841 /** A visitor to write an attribute including its leading |
912 /** A visitor to write an attribute including its leading |
842 * single-character marker. |
913 * single-character marker. |
843 */ |
914 */ |
844 class AttributeWriter implements Attribute.Visitor { |
915 class AttributeWriter implements Attribute.Visitor { |
845 public void visitConstant(Attribute.Constant _value) { |
916 public void visitConstant(Attribute.Constant _value) { |
912 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) { |
983 for (Pair<Symbol.MethodSymbol,Attribute> p : c.values) { |
913 databuf.appendChar(pool.put(p.fst.name)); |
984 databuf.appendChar(pool.put(p.fst.name)); |
914 p.snd.accept(awriter); |
985 p.snd.accept(awriter); |
915 } |
986 } |
916 } |
987 } |
|
988 |
|
989 void writeTypeAnnotation(Attribute.TypeCompound c) { |
|
990 writePosition(c.position); |
|
991 writeCompoundAttribute(c); |
|
992 } |
|
993 |
|
994 void writePosition(TypeAnnotationPosition p) { |
|
995 databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte |
|
996 switch (p.type) { |
|
997 // type cast |
|
998 case CAST: |
|
999 // instanceof |
|
1000 case INSTANCEOF: |
|
1001 // new expression |
|
1002 case NEW: |
|
1003 databuf.appendChar(p.offset); |
|
1004 break; |
|
1005 // local variable |
|
1006 case LOCAL_VARIABLE: |
|
1007 // resource variable |
|
1008 case RESOURCE_VARIABLE: |
|
1009 databuf.appendChar(p.lvarOffset.length); // for table length |
|
1010 for (int i = 0; i < p.lvarOffset.length; ++i) { |
|
1011 databuf.appendChar(p.lvarOffset[i]); |
|
1012 databuf.appendChar(p.lvarLength[i]); |
|
1013 databuf.appendChar(p.lvarIndex[i]); |
|
1014 } |
|
1015 break; |
|
1016 // exception parameter |
|
1017 case EXCEPTION_PARAMETER: |
|
1018 databuf.appendByte(p.exception_index); |
|
1019 break; |
|
1020 // method receiver |
|
1021 case METHOD_RECEIVER: |
|
1022 // Do nothing |
|
1023 break; |
|
1024 // type parameter |
|
1025 case CLASS_TYPE_PARAMETER: |
|
1026 case METHOD_TYPE_PARAMETER: |
|
1027 databuf.appendByte(p.parameter_index); |
|
1028 break; |
|
1029 // type parameter bound |
|
1030 case CLASS_TYPE_PARAMETER_BOUND: |
|
1031 case METHOD_TYPE_PARAMETER_BOUND: |
|
1032 databuf.appendByte(p.parameter_index); |
|
1033 databuf.appendByte(p.bound_index); |
|
1034 break; |
|
1035 // class extends or implements clause |
|
1036 case CLASS_EXTENDS: |
|
1037 databuf.appendChar(p.type_index); |
|
1038 break; |
|
1039 // throws |
|
1040 case THROWS: |
|
1041 databuf.appendChar(p.type_index); |
|
1042 break; |
|
1043 // method parameter |
|
1044 case METHOD_FORMAL_PARAMETER: |
|
1045 databuf.appendByte(p.parameter_index); |
|
1046 break; |
|
1047 // method/constructor/reference type argument |
|
1048 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: |
|
1049 case METHOD_INVOCATION_TYPE_ARGUMENT: |
|
1050 case METHOD_REFERENCE_TYPE_ARGUMENT: |
|
1051 databuf.appendChar(p.offset); |
|
1052 databuf.appendByte(p.type_index); |
|
1053 break; |
|
1054 // We don't need to worry about these |
|
1055 case METHOD_RETURN: |
|
1056 case FIELD: |
|
1057 break; |
|
1058 // lambda formal parameter |
|
1059 case LAMBDA_FORMAL_PARAMETER: |
|
1060 databuf.appendByte(p.parameter_index); |
|
1061 break; |
|
1062 case UNKNOWN: |
|
1063 throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!"); |
|
1064 default: |
|
1065 throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p); |
|
1066 } |
|
1067 |
|
1068 { // Append location data for generics/arrays. |
|
1069 databuf.appendByte(p.location.size()); |
|
1070 java.util.List<Integer> loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location); |
|
1071 for (int i : loc) |
|
1072 databuf.appendByte((byte)i); |
|
1073 } |
|
1074 } |
|
1075 |
917 /********************************************************************** |
1076 /********************************************************************** |
918 * Writing Objects |
1077 * Writing Objects |
919 **********************************************************************/ |
1078 **********************************************************************/ |
920 |
1079 |
921 /** Enter an inner class into the `innerClasses' set/queue. |
1080 /** Enter an inner class into the `innerClasses' set/queue. |
1659 acount++; |
1818 acount++; |
1660 } |
1819 } |
1661 |
1820 |
1662 acount += writeFlagAttrs(c.flags()); |
1821 acount += writeFlagAttrs(c.flags()); |
1663 acount += writeJavaAnnotations(c.getRawAttributes()); |
1822 acount += writeJavaAnnotations(c.getRawAttributes()); |
|
1823 acount += writeTypeAnnotations(c.getRawTypeAttributes()); |
1664 acount += writeEnclosingMethodAttribute(c); |
1824 acount += writeEnclosingMethodAttribute(c); |
1665 acount += writeExtraClassAttributes(c); |
1825 acount += writeExtraClassAttributes(c); |
1666 |
1826 |
1667 poolbuf.appendInt(JAVA_MAGIC); |
1827 poolbuf.appendInt(JAVA_MAGIC); |
1668 poolbuf.appendChar(target.minorVersion); |
1828 poolbuf.appendChar(target.minorVersion); |