IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ClassFile.Method.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2015 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using IKVM.Attributes;
25using IKVM.ByteCode;
26using IKVM.ByteCode.Decoding;
28
29#if IMPORTER
31#endif
32
33namespace IKVM.Runtime
34{
35
36 sealed partial class ClassFile
37 {
38
39 internal sealed partial class Method : FieldOrMethod
40 {
41
42 Code code;
43 string[] exceptions;
44 LowFreqData low;
45 MethodParametersEntry[] parameters;
46
55 internal Method(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options, IKVM.ByteCode.Decoding.Method reader) :
56 base(classFile, utf8_cp, reader.AccessFlags, reader.Name, reader.Descriptor)
57 {
58 // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit>
59 // however, since Java 7 it does need to be marked static
60 if (ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && (classFile.MajorVersion < 51 || IsStatic))
61 {
62 accessFlags &= Modifiers.Strictfp;
63 accessFlags |= (Modifiers.Static | Modifiers.Private);
64 }
65 else
66 {
67 // LAMESPEC: vmspec 4.6 says that abstract methods can not be strictfp (and this makes sense), but
68 // javac (pre 1.5) is broken and marks abstract methods as strictfp (if you put the strictfp on the class)
69 if ((ReferenceEquals(Name, StringConstants.INIT) && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative))
70 || (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
71 || (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized))
72 || (classFile.IsInterface && classFile.MajorVersion <= 51 && (!IsPublic || IsFinal || IsNative || IsSynchronized || !IsAbstract))
73 || (classFile.IsInterface && classFile.MajorVersion >= 52 && (!(IsPublic || IsPrivate) || IsFinal || IsNative || IsSynchronized)))
74 {
75 throw new ClassFormatError("Method {0} in class {1} has illegal modifiers: 0x{2:X}", Name, classFile.Name, (int)accessFlags);
76 }
77 }
78
79 for (int i = 0; i < reader.Attributes.Count; i++)
80 {
81 var attribute = reader.Attributes[i];
82
83 switch (classFile.GetConstantPoolUtf8String(utf8_cp, attribute.Name))
84 {
85 case AttributeName.Deprecated:
86 var deprecatedAttribute = (DeprecatedAttribute)attribute;
87 flags |= FLAG_MASK_DEPRECATED;
88 break;
89 case AttributeName.Code:
90 {
91 var codeAttribute = (CodeAttribute)attribute;
92 if (code.IsEmpty == false)
93 throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name);
94
95 code.Read(classFile, utf8_cp, this, codeAttribute, options);
96 break;
97 }
98 case AttributeName.Exceptions:
99 {
100 if (exceptions != null)
101 throw new ClassFormatError("{0} (Duplicate Exceptions attribute)", classFile.Name);
102
103 var exceptionsAttribute = (ExceptionsAttribute)attribute;
104 exceptions = new string[exceptionsAttribute.Exceptions.Count];
105 for (int j = 0; j < exceptionsAttribute.Exceptions.Count; j++)
106 exceptions[j] = classFile.GetConstantPoolClass(exceptionsAttribute.Exceptions[j]);
107
108 break;
109 }
110 case AttributeName.Signature:
111 if (classFile.MajorVersion < 49)
112 goto default;
113
114 var signatureAttribute = (IKVM.ByteCode.Decoding.SignatureAttribute)attribute;
115 signature = classFile.GetConstantPoolUtf8String(utf8_cp, signatureAttribute.Signature);
116 break;
117 case AttributeName.RuntimeVisibleAnnotations:
118 if (classFile.MajorVersion < 49)
119 goto default;
120
121 var runtimeVisibleAnnotationsAttribute = (RuntimeVisibleAnnotationsAttribute)attribute;
122 annotations = ReadAnnotations(runtimeVisibleAnnotationsAttribute.Annotations, classFile, utf8_cp);
123 if ((options & ClassFileParseOptions.TrustedAnnotations) != 0)
124 {
125 foreach (object[] annot in annotations)
126 {
127 switch ((string)annot[1])
128 {
129#if IMPORTER
130 case "Lsun/reflect/CallerSensitive;":
131 flags |= FLAG_CALLERSENSITIVE;
132 break;
133#endif
134 case "Ljava/lang/invoke/LambdaForm$Compiled;":
135 flags |= FLAG_LAMBDAFORM_COMPILED;
136 break;
137 case "Ljava/lang/invoke/LambdaForm$Hidden;":
138 flags |= FLAG_LAMBDAFORM_HIDDEN;
139 break;
140 case "Ljava/lang/invoke/ForceInline;":
141 flags |= FLAG_FORCEINLINE;
142 break;
143 }
144 }
145 }
146 break;
147 case AttributeName.RuntimeVisibleParameterAnnotations:
148 if (classFile.MajorVersion < 49)
149 goto default;
150
151 var runtimeVisibleParameterAnnotationsAttribute = (RuntimeVisibleParameterAnnotationsAttribute)attribute;
152 low ??= new LowFreqData();
153 low.parameterAnnotations = new object[runtimeVisibleParameterAnnotationsAttribute.ParameterAnnotations.Count][];
154 for (int j = 0; j < runtimeVisibleParameterAnnotationsAttribute.ParameterAnnotations.Count; j++)
155 {
156 var parameter = runtimeVisibleParameterAnnotationsAttribute.ParameterAnnotations[j];
157 low.parameterAnnotations[j] = new object[parameter.Annotations.Count];
158 for (int k = 0; k < parameter.Annotations.Count; k++)
159 low.parameterAnnotations[j][k] = ReadAnnotation(parameter.Annotations[k], classFile, utf8_cp);
160 }
161
162 break;
163 case AttributeName.AnnotationDefault:
164 if (classFile.MajorVersion < 49)
165 goto default;
166
167 var annotationDefaultAttribute = (IKVM.ByteCode.Decoding.AnnotationDefaultAttribute)attribute;
168 low ??= new LowFreqData();
169 low.annotationDefault = ReadAnnotationElementValue(annotationDefaultAttribute.DefaultValue, classFile, utf8_cp);
170
171 break;
172#if IMPORTER
173 case AttributeName.RuntimeInvisibleAnnotations:
174 if (classFile.MajorVersion < 49)
175 goto default;
176
177 var runtimeInvisibleAnnotationsAttribute = (RuntimeInvisibleAnnotationsAttribute)attribute;
178
179 foreach (object[] annot in ReadAnnotations(runtimeInvisibleAnnotationsAttribute.Annotations, classFile, utf8_cp))
180 {
181 if (annot[1].Equals("Likvm/lang/Internal;"))
182 {
183 if (classFile.IsInterface)
184 {
185 classFile.diagnostics.InterfaceMethodCantBeInternal(classFile.Name, Name, Signature);
186 }
187 else
188 {
189 accessFlags &= ~Modifiers.AccessMask;
190 flags |= FLAG_MASK_INTERNAL;
191 }
192 }
193 else if (annot[1].Equals("Likvm/internal/InterlockedCompareAndSet;"))
194 {
195 string field = null;
196 for (int j = 2; j < annot.Length; j += 2)
197 if (annot[j].Equals("value") && annot[j + 1] is string)
198 field = (string)annot[j + 1];
199
200 if (field != null)
201 {
202 low ??= new LowFreqData();
203 low.InterlockedCompareAndSetField = field;
204 }
205 }
206 else if (annot[1].Equals("Likvm/lang/ModuleInitializer;"))
207 {
208 if (classFile.IsInterface || IsConstructor || IsClassInitializer || IsPrivate || IsStatic == false)
209 {
210 classFile.diagnostics.ModuleInitializerMethodRequirements(classFile.Name, Name, Signature);
211 }
212 else
213 {
214 flags |= FLAG_MODULE_INITIALIZER;
215 }
216 }
217 }
218
219 break;
220#endif
221 case AttributeName.MethodParameters:
222 if (classFile.MajorVersion < 52)
223 goto default;
224
225 if (parameters != null)
226 throw new ClassFormatError("{0} (Duplicate MethodParameters attribute)", classFile.Name);
227
228 var methodParametersAttribute = (IKVM.ByteCode.Decoding.MethodParametersAttribute)attribute;
229 parameters = ReadMethodParameters(methodParametersAttribute.Parameters, utf8_cp);
230
231 break;
232 case AttributeName.RuntimeVisibleTypeAnnotations:
233 if (classFile.MajorVersion < 52)
234 goto default;
235
236 var runtimeVisibleTypeAnnotationsAttribute = (IKVM.ByteCode.Decoding.RuntimeVisibleTypeAnnotationsAttribute)attribute;
237 classFile.CreateUtf8ConstantPoolItems(utf8_cp);
238 runtimeVisibleTypeAnnotations = runtimeVisibleTypeAnnotationsAttribute.TypeAnnotations;
239 break;
240 default:
241 break;
242 }
243 }
244 if (IsAbstract || IsNative)
245 {
246 if (!code.IsEmpty)
247 {
248 throw new ClassFormatError("Code attribute in native or abstract methods in class file " + classFile.Name);
249 }
250 }
251 else
252 {
253 if (code.IsEmpty)
254 {
255 if (ReferenceEquals(this.Name, StringConstants.CLINIT))
256 {
257 code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature);
258 return;
259 }
260 throw new ClassFormatError("Absent Code attribute in method that is not native or abstract in class file " + classFile.Name);
261 }
262 }
263 }
264
265 private static MethodParametersEntry[] ReadMethodParameters(MethodParameterTable parameters, string[] utf8_cp)
266 {
267 var l = new MethodParametersEntry[parameters.Count];
268
269 for (int i = 0; i < parameters.Count; i++)
270 {
271 var name = parameters[i].Name;
272 if (name.Slot >= utf8_cp.Length || (name.IsNotNil && utf8_cp[name.Slot] == null))
273 return MethodParametersEntry.Malformed;
274
275 l[i].name = utf8_cp[name.Slot];
276 l[i].accessFlags = parameters[i].AccessFlags;
277 }
278
279 return l;
280 }
281
282 protected override void ValidateSig(ClassFile classFile, string descriptor)
283 {
284 if (!IsValidMethodDescriptor(descriptor))
285 {
286 throw new ClassFormatError("{0} (Method \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor);
287 }
288 }
289
290 internal bool IsStrictfp => (accessFlags & Modifiers.Strictfp) != 0;
291
292 internal bool IsVirtual => (accessFlags & (Modifiers.Static | Modifiers.Private)) == 0 && !IsConstructor;
293
294 // Is this the <clinit>()V method?
295 internal bool IsClassInitializer => ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && IsStatic;
296
297 internal bool IsConstructor => ReferenceEquals(Name, StringConstants.INIT);
298
299 internal bool IsCallerSensitive => (flags & FLAG_CALLERSENSITIVE) != 0;
300
301 internal bool IsLambdaFormCompiled => (flags & FLAG_LAMBDAFORM_COMPILED) != 0;
302
303 internal bool IsLambdaFormHidden => (flags & FLAG_LAMBDAFORM_HIDDEN) != 0;
304
305 internal bool IsForceInline => (flags & FLAG_FORCEINLINE) != 0;
306
307 internal string[] ExceptionsAttribute => exceptions;
308
309 internal object[][] ParameterAnnotations => low == null ? null : low.parameterAnnotations;
310
311 internal object AnnotationDefault => low == null ? null : low.annotationDefault;
312
313#if IMPORTER
314
315 internal string InterlockedCompareAndSetField => low == null ? null : low.InterlockedCompareAndSetField;
316
317#endif
318
319 internal string VerifyError => code.verifyError;
320
321 // maps argument 'slot' (as encoded in the xload/xstore instructions) into the ordinal
322 internal int[] ArgMap => code.argmap;
323
324 internal int MaxStack => code.max_stack;
325
326 internal int MaxLocals => code.max_locals;
327
328 internal Instruction[] Instructions
329 {
330 get => code.instructions;
331 set => code.instructions = value;
332 }
333
334 internal ExceptionTableEntry[] ExceptionTable
335 {
336 get => code.exception_table;
337 set => code.exception_table = value;
338 }
339
340 internal LineNumberTableEntry[] LineNumberTableAttribute => code.lineNumberTable;
341
342 internal LocalVariableTableEntry[] LocalVariableTableAttribute => code.localVariableTable;
343
344 internal MethodParametersEntry[] MethodParameters => parameters;
345
346 internal bool MalformedMethodParameters => parameters == MethodParametersEntry.Malformed;
347
348 internal bool HasJsr => code.hasJsr;
349
350 }
351
352 }
353
354}
global::java.lang.invoke.LambdaForm.Name Name
static bool IsValidMethodDescriptor(string descriptor)
Returns true if the specified descriptor is a valid method descriptor.
Definition ClassFile.cs:220
IKVM.Runtime.ClassFile.Method.Instruction Instruction
Definition compiler.cs:44
IKVM.Runtime.ClassFile.Method.LocalVariableTableEntry LocalVariableTableEntry
Definition compiler.cs:43
IKVM.Runtime.ClassFile.Method.ExceptionTableEntry ExceptionTableEntry
Definition compiler.cs:42