IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
ClassFile.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 System;
25using System.Collections.Generic;
26using System.Linq;
27
28using IKVM.Attributes;
29using IKVM.ByteCode;
30using IKVM.ByteCode.Decoding;
32
33namespace IKVM.Runtime
34{
35
36 sealed partial class ClassFile : IDisposable
37 {
38
45 public static bool IsValidMethodName(string name, ClassFormatVersion version)
46 {
47 if (name is null)
48 throw new ArgumentNullException(nameof(name));
49
50 if (name.Length == 0)
51 return false;
52
53 for (int i = 0; i < name.Length; i++)
54 if (".;[/<>".Contains(name[i]))
55 return false;
56
57 return version >= 49 || IsValidPre49Identifier(name);
58 }
59
66 public static bool IsValidMethodName(ReadOnlySpan<char> name, ClassFormatVersion version)
67 {
68 if (name.Length == 0)
69 return false;
70
71 for (int i = 0; i < name.Length; i++)
72 if (".;[/<>".Contains(name[i]))
73 return false;
74
75 return version >= 49 || IsValidPre49Identifier(name);
76 }
77
84 public static bool IsValidFieldName(string name, ClassFormatVersion version)
85 {
86 if (name is null)
87 throw new ArgumentNullException(nameof(name));
88
89 return IsValidFieldName(name.AsSpan(), version);
90 }
91
98 public static bool IsValidFieldName(ReadOnlySpan<char> name, ClassFormatVersion version)
99 {
100 if (name.Length == 0)
101 return false;
102
103 for (int i = 0; i < name.Length; i++)
104 if (".;[/".Contains(name[i]))
105 return false;
106
107 return version >= 49 || IsValidPre49Identifier(name);
108 }
109
115 public static bool IsValidPre49Identifier(string name)
116 {
117 if (name is null)
118 throw new ArgumentNullException(nameof(name));
119
120 if (!char.IsLetter(name[0]) && "$_".Contains(name[0]) == false)
121 return false;
122
123 for (int i = 1; i < name.Length; i++)
124 if (!char.IsLetterOrDigit(name[i]) && "$_".Contains(name[i]) == false)
125 return false;
126
127 return true;
128 }
129
135 public static bool IsValidPre49Identifier(ReadOnlySpan<char> name)
136 {
137 if (!char.IsLetter(name[0]) && "$_".Contains(name[0]) == false)
138 return false;
139
140 for (int i = 1; i < name.Length; i++)
141 if (!char.IsLetterOrDigit(name[i]) && "$_".Contains(name[i]) == false)
142 return false;
143
144 return true;
145 }
146
152 public static bool IsValidFieldDescriptor(string descriptor)
153 {
154 if (descriptor is null)
155 throw new ArgumentNullException(nameof(descriptor));
156
157 return IsValidFieldDescriptor(descriptor.AsSpan());
158 }
159
165 public static bool IsValidFieldDescriptor(string descriptor, int start, int end)
166 {
167 if (descriptor is null)
168 throw new ArgumentNullException(nameof(descriptor));
169
170 return IsValidFieldDescriptor(descriptor.AsSpan());
171 }
172
178 public static bool IsValidFieldDescriptor(ReadOnlySpan<char> descriptor)
179 {
180 if (descriptor.IsEmpty)
181 return false;
182
183 switch (descriptor[0])
184 {
185 case 'L':
186 // skip L, next semicolon should be last character
187 descriptor = descriptor.Slice(1);
188 return descriptor.Length >= 2 && descriptor.IndexOf(';') == descriptor.Length - 1;
189 case '[':
190 // advance past [ values
191 while (descriptor[0] == '[')
192 {
193 descriptor = descriptor.Slice(1);
194 if (descriptor.IsEmpty)
195 return false;
196 }
197
198 return IsValidFieldDescriptor(descriptor);
199 case 'B':
200 case 'Z':
201 case 'C':
202 case 'S':
203 case 'I':
204 case 'J':
205 case 'F':
206 case 'D':
207 // skip char, should be empty
208 descriptor = descriptor.Slice(1);
209 return descriptor.IsEmpty;
210 default:
211 return false;
212 }
213 }
214
220 public static bool IsValidMethodDescriptor(string descriptor)
221 {
222 if (descriptor is null)
223 throw new ArgumentNullException(nameof(descriptor));
224
225 return IsValidMethodDescriptor(descriptor.AsSpan());
226 }
227
233 public static bool IsValidMethodDescriptor(ReadOnlySpan<char> descriptor)
234 {
235 if (descriptor.Length < 3 || descriptor[0] != '(')
236 return false;
237
238 int end = descriptor.IndexOf(')');
239 if (end == -1)
240 return false;
241
242 if (!descriptor.EndsWith(")V".AsSpan()) && !IsValidFieldDescriptor(descriptor[(end + 1)..]))
243 return false;
244
245 for (int i = 1; i < end; i++)
246 {
247 switch (descriptor[i])
248 {
249 case 'B':
250 case 'Z':
251 case 'C':
252 case 'S':
253 case 'I':
254 case 'J':
255 case 'F':
256 case 'D':
257 break;
258 case 'L':
259 var p = descriptor.Slice(i).IndexOf(';');
260 i = p == -1 ? -1 : p + i;
261 break;
262 case '[':
263 while (descriptor[i] == '[')
264 i++;
265
266 if ("BZCSIJFDL".Contains(descriptor[i]) == false)
267 return false;
268
269 if (descriptor[i] == 'L')
270 {
271 var o = descriptor.Slice(i).IndexOf(';');
272 i = o == -1 ? -1 : o + i;
273 }
274
275 break;
276 default:
277 return false;
278 }
279
280 if (i == -1 || i >= end)
281 return false;
282 }
283
284 return true;
285 }
286
287 const ushort FLAG_MASK_DEPRECATED = 0x100;
288 const ushort FLAG_MASK_INTERNAL = 0x200;
289 const ushort FLAG_CALLERSENSITIVE = 0x400;
290 const ushort FLAG_LAMBDAFORM_COMPILED = 0x800;
291 const ushort FLAG_LAMBDAFORM_HIDDEN = 0x1000;
292 const ushort FLAG_FORCEINLINE = 0x2000;
293 const ushort FLAG_HAS_ASSERTIONS = 0x4000;
294 const ushort FLAG_MODULE_INITIALIZER = 0x8000;
295
296 readonly RuntimeContext context;
297 readonly IDiagnosticHandler diagnostics;
298 readonly IKVM.ByteCode.Decoding.ClassFile clazz;
299
300 readonly ConstantPoolItem[] constantpool;
301 readonly string[] utf8_cp;
302
303 Modifiers access_flags;
304 ushort flags;
305 readonly ConstantPoolItemClass[] interfaces;
306 readonly Field[] fields;
307 readonly Method[] methods;
308 readonly string sourceFile;
309#if IMPORTER
310 string sourcePath;
311#endif
312 readonly string ikvmAssembly;
313 readonly InnerClass[] innerClasses;
314 readonly object[] annotations;
315 readonly string signature;
316 readonly string[] enclosingMethod;
317 readonly BootstrapMethod[] bootstrapMethods;
318 readonly TypeAnnotationTable runtimeVisibleTypeAnnotations = TypeAnnotationTable.Empty;
319
320#if IMPORTER
321
330 internal static string GetClassName(byte[] bytes, int offset, int length, out bool isstub)
331 {
332 try
333 {
334 using var clazz = IKVM.ByteCode.Decoding.ClassFile.Read(bytes.AsMemory(offset, length));
335 return GetClassName(clazz, out isstub);
336 }
337 catch (UnsupportedClassVersionException e)
338 {
339 throw new UnsupportedClassVersionError(e.Message);
340 }
341 catch (ByteCodeException e)
342 {
343 throw new ClassFormatError(e.Message);
344 }
345 }
346
355 static string GetClassName(IKVM.ByteCode.Decoding.ClassFile reader, out bool isstub)
356 {
357 if (reader.Version < new ClassFormatVersion(45, 3) || reader.Version > new ClassFormatVersion((ushort)SupportedVersions.Maximum, 0))
358 throw new UnsupportedClassVersionError(reader.Version);
359
360 // this is a terrible way to go about encoding this information
361 isstub = reader.Constants.Any(i => i.Kind == ConstantKind.Utf8 && reader.Constants.Get((Utf8ConstantHandle)i).Value == "IKVM.NET.Assembly");
362 return string.Intern(reader.Constants.Get(reader.This).Name.Replace('/', '.'));
363 }
364
365#endif
366
378 internal ClassFile(RuntimeContext context, IDiagnosticHandler diagnostics, IKVM.ByteCode.Decoding.ClassFile clazz, string inputClassName, ClassFileParseOptions options, object[] constantPoolPatches)
379 {
380 this.context = context ?? throw new ArgumentNullException(nameof(context));
381 this.diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
382 this.clazz = clazz ?? throw new ArgumentNullException(nameof(clazz));
383
384 try
385 {
386 if (clazz.Version < new ClassFormatVersion(45, 3) || clazz.Version > new ClassFormatVersion((ushort)SupportedVersions.Maximum, 0))
387 throw new UnsupportedClassVersionError(clazz.Version);
388
389 // load a copy of the constant pool using our own custom class hierarchy, reading data from IKVM.ByteCdoe
390 constantpool = new ConstantPoolItem[clazz.Constants.SlotCount];
391 utf8_cp = new string[clazz.Constants.SlotCount];
392 for (ushort i = 1; i < clazz.Constants.SlotCount; i++)
393 {
394 switch (clazz.Constants.GetKind(new ConstantHandle(ConstantKind.Unknown, i)))
395 {
396 case ConstantKind.Unknown:
397 // longs and doubles can leave holes in the constant pool
398 break;
399 case ConstantKind.Class:
400 constantpool[i] = new ConstantPoolItemClass(context, clazz.Constants.Read(new ClassConstantHandle(i)));
401 break;
402 case ConstantKind.Double:
403 constantpool[i] = new ConstantPoolItemDouble(context, clazz.Constants.Read(new DoubleConstantHandle(i)));
404 break;
405 case ConstantKind.Fieldref:
406 constantpool[i] = new ConstantPoolItemFieldref(context, clazz.Constants.Read(new FieldrefConstantHandle(i)));
407 break;
408 case ConstantKind.Float:
409 constantpool[i] = new ConstantPoolItemFloat(context, clazz.Constants.Read(new FloatConstantHandle(i)));
410 break;
411 case ConstantKind.Integer:
412 constantpool[i] = new ConstantPoolItemInteger(context, clazz.Constants.Read(new IntegerConstantHandle(i)));
413 break;
414 case ConstantKind.InterfaceMethodref:
415 constantpool[i] = new ConstantPoolItemInterfaceMethodref(context, clazz.Constants.Read(new InterfaceMethodrefConstantHandle(i)));
416 break;
417 case ConstantKind.Long:
418 constantpool[i] = new ConstantPoolItemLong(context, clazz.Constants.Read(new LongConstantHandle(i)));
419 break;
420 case ConstantKind.Methodref:
421 constantpool[i] = new ConstantPoolItemMethodref(context, clazz.Constants.Read(new MethodrefConstantHandle(i)));
422 break;
423 case ConstantKind.NameAndType:
424 constantpool[i] = new ConstantPoolItemNameAndType(context, clazz.Constants.Read(new NameAndTypeConstantHandle(i)));
425 break;
426 case ConstantKind.MethodHandle:
427 if (clazz.Version < 51)
428 goto default;
429 constantpool[i] = new ConstantPoolItemMethodHandle(context, clazz.Constants.Read(new MethodHandleConstantHandle(i)));
430 break;
431 case ConstantKind.MethodType:
432 if (clazz.Version < 51)
433 goto default;
434 constantpool[i] = new ConstantPoolItemMethodType(context, clazz.Constants.Read(new MethodTypeConstantHandle(i)));
435 break;
436 case ConstantKind.InvokeDynamic:
437 if (clazz.Version < 51)
438 goto default;
439 constantpool[i] = new ConstantPoolItemInvokeDynamic(context, clazz.Constants.Read(new InvokeDynamicConstantHandle(i)));
440 break;
441 case ConstantKind.String:
442 constantpool[i] = new ConstantPoolItemString(context, clazz.Constants.Read(new StringConstantHandle(i)));
443 break;
444 case ConstantKind.Utf8:
445 utf8_cp[i] = clazz.Constants.Read(new Utf8ConstantHandle(i)).Value;
446 break;
447 default:
448 throw new ClassFormatError("Unknown constant type.");
449 }
450 }
451
452 if (constantPoolPatches != null)
453 PatchConstantPool(constantPoolPatches, utf8_cp, inputClassName);
454
455 for (int i = 1; i < clazz.Constants.SlotCount; i++)
456 {
457 if (constantpool[i] != null)
458 {
459 try
460 {
461 constantpool[i].Resolve(this, utf8_cp, options);
462 }
463 catch (ClassFormatError x)
464 {
465 // HACK at this point we don't yet have the class name, so any exceptions throw
466 // are missing the class name
467 throw new ClassFormatError("{0} ({1})", inputClassName, x.Message);
468 }
469 catch (IndexOutOfRangeException)
470 {
471 throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i);
472 }
473 catch (InvalidCastException)
474 {
475 throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i);
476 }
477 }
478 }
479
480 access_flags = (Modifiers)clazz.AccessFlags;
481
482 // NOTE although the vmspec says (in 4.1) that interfaces must be marked abstract, earlier versions of
483 // javac (JDK 1.1) didn't do this, so the VM doesn't enforce this rule for older class files.
484 // NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this
485 // for older class files.
486 // (See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6320322)
487 if ((IsInterface && IsFinal) || (IsAbstract && IsFinal) || (clazz.Version >= 49 && IsAnnotation && !IsInterface) || (clazz.Version >= 49 && IsInterface && (!IsAbstract || IsSuper || IsEnum)))
488 throw new ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags);
489
490 ValidateConstantPoolItemClass(inputClassName, clazz.This);
491 ValidateConstantPoolItemClass(inputClassName, clazz.Super);
492
493 if (IsInterface && (clazz.Super.IsNil || SuperClass.Name != "java.lang.Object"))
494 throw new ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name);
495
496 // most checks are already done by ConstantPoolItemClass.Resolve, but since it allows
497 // array types, we do need to check for that
498 if (Name[0] == '[')
499 throw new ClassFormatError("Bad name");
500
501 interfaces = new ConstantPoolItemClass[clazz.Interfaces.Count];
502 for (int i = 0; i < interfaces.Length; i++)
503 {
504 var handle = clazz.Interfaces[i].Class;
505 if (handle.IsNil || handle.Slot >= constantpool.Length)
506 throw new ClassFormatError("{0} (Illegal constant pool index)", Name);
507
508 var cpi = constantpool[handle.Slot] as ConstantPoolItemClass;
509 if (cpi == null)
510 throw new ClassFormatError("{0} (Interface name has bad constant type)", Name);
511
512 interfaces[i] = cpi;
513 }
514
515 CheckDuplicates(interfaces, "Repetitive interface name");
516
517 fields = new Field[clazz.Fields.Count];
518 for (int i = 0; i < clazz.Fields.Count; i++)
519 {
520 fields[i] = new Field(this, utf8_cp, clazz.Fields[i]);
521 var name = fields[i].Name;
522
523 if (IsValidFieldName(name, clazz.Version) == false)
524 throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name);
525 }
526
527 CheckDuplicates<FieldOrMethod>(fields, "Repetitive field name/signature");
528
529 methods = new Method[clazz.Methods.Count];
530 for (int i = 0; i < clazz.Methods.Count; i++)
531 {
532 methods[i] = new Method(this, utf8_cp, options, clazz.Methods[i]);
533 var name = methods[i].Name;
534 var sig = methods[i].Signature;
535 if (IsValidMethodName(name, clazz.Version) == false)
536 {
537 if (!ReferenceEquals(name, StringConstants.INIT) && !ReferenceEquals(name, StringConstants.CLINIT))
538 throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name);
539 if (!sig.EndsWith("V"))
540 throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig);
541 if ((options & ClassFileParseOptions.RemoveAssertions) != 0 && methods[i].IsClassInitializer)
542 RemoveAssertionInit(methods[i]);
543 }
544 }
545
546 CheckDuplicates<FieldOrMethod>(methods, "Repetitive method name/signature");
547
548 for (int i = 0; i < clazz.Attributes.Count; i++)
549 {
550 var attribute = clazz.Attributes[i];
551
552 switch (GetConstantPoolUtf8String(utf8_cp, attribute.Name))
553 {
554 case AttributeName.Deprecated:
555 var deprecatedAttribute = (DeprecatedAttribute)attribute;
556 flags |= FLAG_MASK_DEPRECATED;
557 break;
558 case AttributeName.SourceFile:
559 var sourceFileAttribute = (IKVM.ByteCode.Decoding.SourceFileAttribute)attribute;
560 sourceFile = GetConstantPoolUtf8String(utf8_cp, sourceFileAttribute.SourceFile);
561 break;
562 case AttributeName.InnerClasses:
563 if (MajorVersion < 49)
564 goto default;
565
566 var innerClassesAttribute = (InnerClassesAttribute)attribute;
567 innerClasses = new InnerClass[innerClassesAttribute.Table.Count];
568 for (int j = 0; j < innerClasses.Length; j++)
569 {
570 var item = innerClassesAttribute.Table[j];
571
572 innerClasses[j].innerClass = item.Inner;
573 innerClasses[j].outerClass = item.Outer;
574 innerClasses[j].name = item.InnerName;
575 innerClasses[j].accessFlags = (Modifiers)item.InnerAccessFlags;
576
577 if (innerClasses[j].innerClass.IsNotNil && !(GetConstantPoolItem(innerClasses[j].innerClass) is ConstantPoolItemClass))
578 throw new ClassFormatError("{0} (inner_class_info_index has bad constant pool index)", this.Name);
579
580 if (innerClasses[j].outerClass.IsNotNil && !(GetConstantPoolItem(innerClasses[j].outerClass) is ConstantPoolItemClass))
581 throw new ClassFormatError("{0} (outer_class_info_index has bad constant pool index)", this.Name);
582
583 if (innerClasses[j].name.IsNotNil && utf8_cp[innerClasses[j].name.Slot] == null)
584 throw new ClassFormatError("{0} (inner class name has bad constant pool index)", this.Name);
585
586 if (innerClasses[j].innerClass == innerClasses[j].outerClass)
587 throw new ClassFormatError("{0} (Class is both inner and outer class)", this.Name);
588
589 if (innerClasses[j].innerClass.IsNotNil && innerClasses[j].outerClass.IsNotNil)
590 {
591 MarkLinkRequiredConstantPoolItem(innerClasses[j].innerClass);
592 MarkLinkRequiredConstantPoolItem(innerClasses[j].outerClass);
593 }
594 }
595
596 break;
597 case AttributeName.Signature:
598 if (clazz.Version < 49)
599 goto default;
600
601 var signatureAttribute = (IKVM.ByteCode.Decoding.SignatureAttribute)attribute;
602 signature = GetConstantPoolUtf8String(utf8_cp, signatureAttribute.Signature);
603 break;
604 case AttributeName.EnclosingMethod:
605 if (clazz.Version < 49)
606 goto default;
607
608 var enclosingMethodAttribute = (IKVM.ByteCode.Decoding.EnclosingMethodAttribute)attribute;
609 var classHandle = enclosingMethodAttribute.Class;
610 var methodHandle = enclosingMethodAttribute.Method;
611 ValidateConstantPoolItemClass(inputClassName, classHandle);
612
613 if (methodHandle.IsNil)
614 {
615 enclosingMethod =
616 [
617 GetConstantPoolClass(classHandle),
618 null,
619 null
620 ];
621 }
622 else
623 {
624 if (GetConstantPoolItem(methodHandle) is not ConstantPoolItemNameAndType m)
625 throw new ClassFormatError("{0} (Bad constant pool index #{1})", inputClassName, methodHandle);
626
627 enclosingMethod = new string[]
628 {
629 GetConstantPoolClass(classHandle),
630 GetConstantPoolUtf8String(utf8_cp, m.NameHandle),
631 GetConstantPoolUtf8String(utf8_cp, m.DescriptorHandle).Replace('/', '.')
632 };
633 }
634
635 break;
636 case AttributeName.RuntimeVisibleAnnotations:
637 if (clazz.Version < 49)
638 goto default;
639
640 var runtimeVisibleAnnotationsAttribute = (RuntimeVisibleAnnotationsAttribute)attribute;
641 annotations = ReadAnnotations(runtimeVisibleAnnotationsAttribute.Annotations, this, utf8_cp);
642 break;
643#if IMPORTER
644 case AttributeName.RuntimeInvisibleAnnotations:
645 if (clazz.Version < 49)
646 goto default;
647
648 var runtimeInvisibleAnnotationsAttribute = (RuntimeInvisibleAnnotationsAttribute)attribute;
649 foreach (var annot in ReadAnnotations(runtimeInvisibleAnnotationsAttribute.Annotations, this, utf8_cp))
650 {
651 if (annot[1].Equals("Likvm/lang/Internal;"))
652 {
653 access_flags &= ~Modifiers.AccessMask;
654 flags |= FLAG_MASK_INTERNAL;
655 }
656 }
657
658 break;
659#endif
660 case AttributeName.BootstrapMethods:
661 if (clazz.Version < 51)
662 goto default;
663
664 var bootstrapMethodsAttribute = (BootstrapMethodsAttribute)attribute;
665 bootstrapMethods = ReadBootstrapMethods(bootstrapMethodsAttribute.Methods, this);
666 break;
667 case AttributeName.RuntimeVisibleTypeAnnotations:
668 if (clazz.Version < 52)
669 goto default;
670
671 var _runtimeVisibleTypeAnnotations = (IKVM.ByteCode.Decoding.RuntimeVisibleTypeAnnotationsAttribute)attribute;
672 CreateUtf8ConstantPoolItems(utf8_cp);
673 runtimeVisibleTypeAnnotations = _runtimeVisibleTypeAnnotations.TypeAnnotations;
674 break;
675 case "IKVM.NET.Assembly":
676 if (attribute.Data.Length != 2)
677 throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length");
678
679 var r = new ClassFormatReader(attribute.Data);
680 if (r.TryReadU2(out var index) == false)
681 throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length");
682
683 ikvmAssembly = GetConstantPoolUtf8String(utf8_cp, new(index));
684 break;
685 default:
686 break;
687 }
688 }
689
690 // validate the invokedynamic entries to point into the bootstrapMethods array
691 for (int i = 1; i < constantpool.Length; i++)
692 if (constantpool[i] != null && constantpool[i] is ConstantPoolItemInvokeDynamic cpi)
693 if (bootstrapMethods == null || cpi.BootstrapMethod >= bootstrapMethods.Length)
694 throw new ClassFormatError("Short length on BootstrapMethods in class file");
695 }
696 catch (OverflowException)
697 {
698 throw new ClassFormatError("Truncated class file (or section)");
699 }
700 catch (IndexOutOfRangeException)
701 {
702 throw new ClassFormatError("Unspecified class file format error");
703 }
704 catch (ByteCodeException)
705 {
706 throw new ClassFormatError("Unspecified class file format error");
707 }
708 }
709
710 void CreateUtf8ConstantPoolItems(string[] utf8_cp)
711 {
712 for (int i = 0; i < constantpool.Length; i++)
713 if (constantpool[i] == null && utf8_cp[i] != null)
714 constantpool[i] = new ConstantPoolItemUtf8(context, utf8_cp[i]);
715 }
716
717 void CheckDuplicates<T>(T[] members, string msg)
718 where T : IEquatable<T>
719 {
720 if (members.Length < 100)
721 {
722 for (int i = 0; i < members.Length; i++)
723 for (int j = 0; j < i; j++)
724 if (members[i].Equals(members[j]))
725 throw new ClassFormatError("{0} ({1})", Name, msg);
726 }
727 else
728 {
729 var hs = new HashSet<T>();
730 for (int i = 0; i < members.Length; i++)
731 if (hs.Add(members[i]) == false)
732 throw new ClassFormatError("{0} ({1})", Name, msg);
733 }
734 }
735
736 void PatchConstantPool(object[] constantPoolPatches, string[] utf8_cp, string inputClassName)
737 {
738#if !IMPORTER && !FIRST_PASS
739 for (int i = 0; i < constantPoolPatches.Length; i++)
740 {
741 if (constantPoolPatches[i] != null)
742 {
743 if (utf8_cp[i] != null)
744 {
745 if (!(constantPoolPatches[i] is string))
746 throw new ClassFormatError("Illegal utf8 patch at {0} in class file {1}", i, inputClassName);
747
748 utf8_cp[i] = (string)constantPoolPatches[i];
749 }
750 else if (constantpool[i] != null)
751 {
752 switch (constantpool[i].GetConstantType())
753 {
754 case ConstantType.String:
755 constantpool[i] = new ConstantPoolItemLiveObject(context, constantPoolPatches[i]);
756 break;
757 case ConstantType.Class:
758 java.lang.Class clazz;
759 string name;
760 if ((clazz = constantPoolPatches[i] as java.lang.Class) != null)
761 {
762 var tw = RuntimeJavaType.FromClass(clazz);
763 constantpool[i] = new ConstantPoolItemClass(context, tw.Name, tw);
764 }
765 else if ((name = constantPoolPatches[i] as string) != null)
766 {
767 constantpool[i] = new ConstantPoolItemClass(context, string.Intern(name.Replace('/', '.')), null);
768 }
769 else
770 {
771 throw new ClassFormatError("Illegal class patch at {0} in class file {1}", i, inputClassName);
772 }
773 break;
774 case ConstantType.Integer:
775 ((ConstantPoolItemInteger)constantpool[i])._value = ((java.lang.Integer)constantPoolPatches[i]).intValue();
776 break;
777 case ConstantType.Long:
778 ((ConstantPoolItemLong)constantpool[i])._value = ((java.lang.Long)constantPoolPatches[i]).longValue();
779 break;
780 case ConstantType.Float:
781 ((ConstantPoolItemFloat)constantpool[i])._value = ((java.lang.Float)constantPoolPatches[i]).floatValue();
782 break;
783 case ConstantType.Double:
784 ((ConstantPoolItemDouble)constantpool[i])._value = ((java.lang.Double)constantPoolPatches[i]).doubleValue();
785 break;
786 default:
787 throw new NotImplementedException("ConstantPoolPatch: " + constantPoolPatches[i]);
788 }
789 }
790 }
791 }
792#endif
793 }
794
795 void MarkLinkRequiredConstantPoolItem(ConstantHandle handle)
796 {
797 if (handle.Slot > 0 && handle.Slot < constantpool.Length && constantpool[handle.Slot] != null)
798 constantpool[handle.Slot].MarkLinkRequired();
799 }
800
801 void MarkLinkRequiredConstantPoolItem(int index)
802 {
803 MarkLinkRequiredConstantPoolItem(new ConstantHandle(ConstantKind.Unknown, checked((ushort)index)));
804 }
805
806 static BootstrapMethod[] ReadBootstrapMethods(BootstrapMethodTable methods, ClassFile classFile)
807 {
808 var bsm = new BootstrapMethod[methods.Count];
809 for (int i = 0; i < methods.Count; i++)
810 {
811 var method = methods[i];
812
813 var bsm_index = method.Method;
814 if (bsm_index.Slot >= classFile.constantpool.Length || classFile.constantpool[bsm_index.Slot] is not ConstantPoolItemMethodHandle)
815 throw new ClassFormatError("bootstrap_method_index {0} has bad constant type in class file {1}", bsm_index, classFile.Name);
816
817 classFile.MarkLinkRequiredConstantPoolItem(bsm_index);
818
819 var argument_count = method.Arguments.Count;
820 var args = new ConstantHandle[argument_count];
821 for (int j = 0; j < args.Length; j++)
822 {
823 var argument_index = method.Arguments[j];
824 if (classFile.IsValidConstant(argument_index) == false)
825 throw new ClassFormatError("argument_index {0} has bad constant type in class file {1}", argument_index, classFile.Name);
826
827 classFile.MarkLinkRequiredConstantPoolItem(argument_index);
828 args[j] = argument_index;
829 }
830
831 bsm[i] = new BootstrapMethod(bsm_index, args);
832 }
833
834 return bsm;
835 }
836
837 bool IsValidConstant(ConstantHandle handle)
838 {
839 if (handle.Slot < constantpool.Length && constantpool[handle.Slot] != null)
840 {
841 try
842 {
843 constantpool[handle.Slot].GetConstantType();
844 return true;
845 }
846 catch (InvalidOperationException)
847 {
848
849 }
850 }
851
852 return false;
853 }
854
855 static object[][] ReadAnnotations(AnnotationTable reader, ClassFile classFile, string[] utf8_cp)
856 {
857 var annotations = new object[reader.Count][];
858
859 for (int i = 0; i < annotations.Length; i++)
860 annotations[i] = ReadAnnotation(reader[i], classFile, utf8_cp);
861
862 return annotations;
863 }
864
865 static object[] ReadAnnotation(IKVM.ByteCode.Decoding.Annotation annotation, ClassFile classFile, string[] utf8_cp)
866 {
867 var l = new object[2 + annotation.Elements.Count * 2];
869 l[1] = classFile.GetConstantPoolUtf8String(utf8_cp, annotation.Type);
870 for (int i = 0; i < annotation.Elements.Count; i++)
871 {
872 l[2 + i * 2 + 0] = classFile.GetConstantPoolUtf8String(utf8_cp, annotation.Elements[i].Name);
873 l[2 + i * 2 + 1] = ReadAnnotationElementValue(annotation.Elements[i].Value, classFile, utf8_cp);
874 }
875
876 return l;
877 }
878
879 static object ReadAnnotationElementValue(in ElementValue reader, ClassFile classFile, string[] utf8_cp)
880 {
881 try
882 {
883 switch (reader.Kind)
884 {
885 case ElementValueKind.Boolean:
886 return classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle) != 0;
887 case ElementValueKind.Byte:
888 return (byte)classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
889 case ElementValueKind.Char:
890 return (char)classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
891 case ElementValueKind.Short:
892 return (short)classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
893 case ElementValueKind.Integer:
894 return classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
895 case ElementValueKind.Float:
896 return classFile.GetConstantPoolConstantFloat((FloatConstantHandle)((ConstantElementValue)reader).Handle);
897 case ElementValueKind.Long:
898 return classFile.GetConstantPoolConstantLong((LongConstantHandle)((ConstantElementValue)reader).Handle);
899 case ElementValueKind.Double:
900 return classFile.GetConstantPoolConstantDouble((DoubleConstantHandle)((ConstantElementValue)reader).Handle);
901 case ElementValueKind.String:
902 return classFile.GetConstantPoolUtf8String(utf8_cp, (Utf8ConstantHandle)((ConstantElementValue)reader).Handle);
903 case ElementValueKind.Enum:
904 var _enum = (EnumElementValue)reader;
905 return new object[] {
907 classFile.GetConstantPoolUtf8String(utf8_cp, _enum.TypeName),
908 classFile.GetConstantPoolUtf8String(utf8_cp, _enum.ConstantName)
909 };
910 case ElementValueKind.Class:
911 var _class = (ClassElementValue)reader;
912 return new object[] {
914 classFile.GetConstantPoolUtf8String(utf8_cp, _class.Class)
915 };
916 case ElementValueKind.Annotation:
917 return ReadAnnotation(((AnnotationElementValue)reader).Annotation, classFile, utf8_cp);
918 case ElementValueKind.Array:
919 var _array = (ArrayElementValue)reader;
920
921 var array = new object[_array.Count + 1];
923 for (int i = 0; i < _array.Count; i++)
924 array[i + 1] = ReadAnnotationElementValue(_array[i], classFile, utf8_cp);
925
926 return array;
927 default:
928 throw new ClassFormatError("Invalid tag {0} in annotation element_value", reader.Kind);
929 }
930 }
931 catch (NullReferenceException)
932 {
933
934 }
935 catch (InvalidCastException)
936 {
937
938 }
939 catch (IndexOutOfRangeException)
940 {
941
942 }
943 catch (ByteCodeException)
944 {
945
946 }
947
948 return new object[] { IKVM.Attributes.AnnotationDefaultAttribute.TAG_ERROR, "java.lang.IllegalArgumentException", "Wrong type at constant pool index" };
949 }
950
951 void ValidateConstantPoolItemClass(string classFile, ClassConstantHandle handle)
952 {
953 if (handle.Slot >= constantpool.Length || constantpool[handle.Slot] is not ConstantPoolItemClass)
954 throw new ClassFormatError("{0} (Bad constant pool index #{1})", classFile, handle);
955 }
956
960 public int MajorVersion => clazz.Version.Major;
961
967 public void Link(RuntimeJavaType thisType, LoadMode mode)
968 {
969 // this is not just an optimization, it's required for anonymous classes to be able to refer to themselves
970 ((ConstantPoolItemClass)constantpool[clazz.This.Slot]).LinkSelf(thisType);
971
972 for (int i = 1; i < constantpool.Length; i++)
973 if (constantpool[i] != null)
974 constantpool[i].Link(thisType, mode);
975 }
976
980 public Modifiers Modifiers => access_flags;
981
985 public bool IsAbstract => (access_flags & (Modifiers.Abstract | Modifiers.Interface)) != 0;
986
990 public bool IsFinal => (access_flags & Modifiers.Final) != 0;
991
995 public bool IsPublic => (access_flags & Modifiers.Public) != 0;
996
1000 public bool IsInterface => (access_flags & Modifiers.Interface) != 0;
1001
1005 public bool IsEnum => (access_flags & Modifiers.Enum) != 0;
1006
1010 public bool IsAnnotation => (access_flags & Modifiers.Annotation) != 0;
1011
1015 public bool IsSuper => (access_flags & Modifiers.Super) != 0;
1016
1022 internal bool IsReferenced(Field fld) => constantpool.OfType<ConstantPoolItemFieldref>().Any(i => i.Class == Name && i.Name == fld.Name && i.Signature == fld.Signature);
1023
1029 internal ConstantPoolItemFieldref GetFieldref(FieldrefConstantHandle handle)
1030 {
1031 return (ConstantPoolItemFieldref)constantpool[handle.Slot];
1032 }
1033
1039 internal ConstantPoolItemFieldref GetFieldref(int slot)
1040 {
1041 return GetFieldref(new FieldrefConstantHandle(checked((ushort)slot)));
1042 }
1043
1049 internal ConstantPoolItemFieldref SafeGetFieldref(ConstantHandle handle)
1050 {
1051 if (handle.IsNotNil && handle.Slot < constantpool.Length)
1052 return constantpool[handle.Slot] as ConstantPoolItemFieldref;
1053
1054 return null;
1055 }
1056
1062 internal ConstantPoolItemFieldref SafeGetFieldref(int index)
1063 {
1064 if (index > ushort.MaxValue || index < ushort.MinValue)
1065 return null;
1066
1067 return SafeGetFieldref(new ConstantHandle(ConstantKind.Unknown, (ushort)index));
1068 }
1069
1070 internal ConstantPoolItemMI GetMethodref(MethodrefConstantHandle handle)
1071 {
1072 return (ConstantPoolItemMI)constantpool[handle.Slot];
1073 }
1074
1075 // NOTE this returns an MI, because it used for both normal methods and interface methods
1076 internal ConstantPoolItemMI GetMethodref(int handle)
1077 {
1078 return GetMethodref(new MethodrefConstantHandle(checked((ushort)handle)));
1079 }
1080
1086 internal ConstantPoolItemMI SafeGetMethodref(ConstantHandle handle)
1087 {
1088 if (handle.IsNotNil && handle.Slot < constantpool.Length)
1089 return constantpool[handle.Slot] as ConstantPoolItemMI;
1090
1091 return null;
1092 }
1093
1099 internal ConstantPoolItemMI SafeGetMethodref(int slot)
1100 {
1101 if (slot > ushort.MaxValue || slot < ushort.MinValue)
1102 return null;
1103
1104 return SafeGetMethodref(new ConstantHandle(ConstantKind.Unknown, (ushort)slot));
1105 }
1106
1107 internal ConstantPoolItemInvokeDynamic GetInvokeDynamic(InvokeDynamicConstantHandle handle)
1108 {
1109 return (ConstantPoolItemInvokeDynamic)constantpool[handle.Slot];
1110 }
1111
1112 private ConstantPoolItem GetConstantPoolItem(ConstantHandle handle)
1113 {
1114 return constantpool[handle.Slot];
1115 }
1116
1117 internal string GetConstantPoolClass(ClassConstantHandle handle)
1118 {
1119 return ((ConstantPoolItemClass)constantpool[handle.Slot]).Name;
1120 }
1121
1122 private bool SafeIsConstantPoolClass(ClassConstantHandle handle)
1123 {
1124 if (handle.Slot > 0 && handle.Slot < constantpool.Length)
1125 return constantpool[handle.Slot] as ConstantPoolItemClass != null;
1126
1127 return false;
1128 }
1129
1130 internal RuntimeJavaType GetConstantPoolClassType(ClassConstantHandle handle)
1131 {
1132 return ((ConstantPoolItemClass)constantpool[handle.Slot]).GetClassType();
1133 }
1134
1135 internal RuntimeJavaType GetConstantPoolClassType(int slot)
1136 {
1137 return GetConstantPoolClassType(new ClassConstantHandle(checked((ushort)slot)));
1138 }
1139 string GetConstantPoolUtf8String(string[] utf8_cp, Utf8ConstantHandle handle)
1140 {
1141 var s = utf8_cp[handle.Slot];
1142 if (s == null)
1143 {
1144 if (clazz.This.IsNil)
1145 throw new ClassFormatError("Bad constant pool index #{0}", handle);
1146 else
1147 throw new ClassFormatError("{0} (Bad constant pool index #{1})", Name, handle);
1148 }
1149
1150 return s;
1151 }
1152
1153 internal ConstantType GetConstantPoolConstantType(ConstantHandle handle)
1154 {
1155 return constantpool[handle.Slot].GetConstantType();
1156 }
1157
1158 internal ConstantType GetConstantPoolConstantType(int slot)
1159 {
1160 return GetConstantPoolConstantType(new ConstantHandle(ConstantKind.Unknown, checked((ushort)slot)));
1161 }
1162
1163 internal double GetConstantPoolConstantDouble(DoubleConstantHandle handle)
1164 {
1165 return ((ConstantPoolItemDouble)constantpool[handle.Slot]).Value;
1166 }
1167
1168 internal float GetConstantPoolConstantFloat(FloatConstantHandle handle)
1169 {
1170 return ((ConstantPoolItemFloat)constantpool[handle.Slot]).Value;
1171 }
1172
1173 internal int GetConstantPoolConstantInteger(IntegerConstantHandle handle)
1174 {
1175 return ((ConstantPoolItemInteger)constantpool[handle.Slot]).Value;
1176 }
1177
1178 internal long GetConstantPoolConstantLong(LongConstantHandle handle)
1179 {
1180 return ((ConstantPoolItemLong)constantpool[handle.Slot]).Value;
1181 }
1182
1183 internal string GetConstantPoolConstantString(StringConstantHandle handle)
1184 {
1185 return ((ConstantPoolItemString)constantpool[handle.Slot]).Value;
1186 }
1187
1188 internal string GetConstantPoolConstantString(int slot)
1189 {
1190 return GetConstantPoolConstantString(new StringConstantHandle(checked((ushort)slot)));
1191 }
1192
1193 internal ConstantPoolItemMethodHandle GetConstantPoolConstantMethodHandle(MethodHandleConstantHandle handle)
1194 {
1195 return (ConstantPoolItemMethodHandle)constantpool[handle.Slot];
1196 }
1197
1198 internal ConstantPoolItemMethodHandle GetConstantPoolConstantMethodHandle(int slot)
1199 {
1200 return GetConstantPoolConstantMethodHandle(new MethodHandleConstantHandle(checked((ushort)slot)));
1201 }
1202
1203 internal ConstantPoolItemMethodType GetConstantPoolConstantMethodType(MethodTypeConstantHandle handle)
1204 {
1205 return (ConstantPoolItemMethodType)constantpool[handle.Slot];
1206 }
1207
1208 internal ConstantPoolItemMethodType GetConstantPoolConstantMethodType(int slot)
1209 {
1210 return GetConstantPoolConstantMethodType(new MethodTypeConstantHandle(checked((ushort)slot)));
1211 }
1212
1213 internal object GetConstantPoolConstantLiveObject(int slot)
1214 {
1215 return ((ConstantPoolItemLiveObject)constantpool[slot]).Value;
1216 }
1217
1221 internal string Name => GetConstantPoolClass(clazz.This);
1222
1226 internal ConstantPoolItemClass SuperClass => (ConstantPoolItemClass)constantpool[clazz.Super.Slot];
1227
1231 internal Field[] Fields => fields;
1232
1236 internal Method[] Methods => methods;
1237
1241 internal ConstantPoolItemClass[] Interfaces => interfaces;
1242
1243 internal string SourceFileAttribute => sourceFile;
1244
1245 internal string SourcePath
1246 {
1247#if IMPORTER
1248 get { return sourcePath; }
1249 set { sourcePath = value; }
1250#else
1251 get { return sourceFile; }
1252#endif
1253 }
1254
1255 internal object[] Annotations => annotations;
1256
1257 internal string GenericSignature => signature;
1258
1259 internal string[] EnclosingMethod => enclosingMethod;
1260
1261 internal ref readonly TypeAnnotationTable RuntimeVisibleTypeAnnotations => ref runtimeVisibleTypeAnnotations;
1262
1263 internal object[] GetConstantPool()
1264 {
1265 var cp = new object[constantpool.Length];
1266 for (int i = 1; i < cp.Length; i++)
1267 if (constantpool[i] != null)
1268 cp[i] = constantpool[i].GetRuntimeValue();
1269
1270 return cp;
1271 }
1272
1273 internal string IKVMAssemblyAttribute => ikvmAssembly;
1274
1275 internal bool DeprecatedAttribute => (flags & FLAG_MASK_DEPRECATED) != 0;
1276
1280 internal bool IsInternal => (flags & FLAG_MASK_INTERNAL) != 0;
1281
1282 // for use by ikvmc (to implement the -privatepackage option)
1283 internal void SetInternal()
1284 {
1285 access_flags &= ~Modifiers.AccessMask;
1286 flags |= FLAG_MASK_INTERNAL;
1287 }
1288
1289 internal bool HasAssertions => (flags & FLAG_HAS_ASSERTIONS) != 0;
1290
1291 internal bool HasInitializedFields
1292 {
1293 get
1294 {
1295 foreach (Field f in fields)
1296 if (f.IsStatic && !f.IsFinal && f.ConstantValue != null)
1297 return true;
1298
1299 return false;
1300 }
1301 }
1302
1303 internal BootstrapMethod GetBootstrapMethod(int index)
1304 {
1305 return bootstrapMethods[index];
1306 }
1307
1308 internal InnerClass[] InnerClasses => innerClasses;
1309
1310 internal Field GetField(string name, string sig)
1311 {
1312 for (int i = 0; i < fields.Length; i++)
1313 if (fields[i].Name == name && fields[i].Signature == sig)
1314 return fields[i];
1315
1316 return null;
1317 }
1318
1323 void RemoveAssertionInit(Method method)
1324 {
1325 /* We match the following code sequence:
1326 * 0 ldc <class X>
1327 * 2 invokevirtual <Method java/lang/Class desiredAssertionStatus()Z>
1328 * 5 ifne 12
1329 * 8 iconst_1
1330 * 9 goto 13
1331 * 12 iconst_0
1332 * 13 putstatic <Field <this class> boolean <static final field>>
1333 */
1334 ConstantPoolItemFieldref fieldref;
1335 Field field;
1336 if (method.Instructions is [
1337 { NormalizedOpCode: NormalizedByteCode.__ldc },
1338 { NormalizedOpCode: NormalizedByteCode.__invokevirtual },
1339 { NormalizedOpCode: NormalizedByteCode.__ifne },
1340 { NormalizedOpCode: NormalizedByteCode.__iconst },
1341 { NormalizedOpCode: NormalizedByteCode.__goto },
1342 { NormalizedOpCode: NormalizedByteCode.__iconst },
1343 { NormalizedOpCode: NormalizedByteCode.__putstatic },
1344 ..] &&
1345 method.Instructions[0].NormalizedOpCode == NormalizedByteCode.__ldc && SafeIsConstantPoolClass(new ClassConstantHandle(checked((ushort)method.Instructions[0].Arg1))) &&
1346 method.Instructions[1].NormalizedOpCode == NormalizedByteCode.__invokevirtual && IsDesiredAssertionStatusMethodref(method.Instructions[1].Arg1) &&
1347 method.Instructions[2].NormalizedOpCode == NormalizedByteCode.__ifne && method.Instructions[2].TargetIndex == 5 &&
1348 method.Instructions[3].NormalizedOpCode == NormalizedByteCode.__iconst && method.Instructions[3].Arg1 == 1 &&
1349 method.Instructions[4].NormalizedOpCode == NormalizedByteCode.__goto && method.Instructions[4].TargetIndex == 6 &&
1350 method.Instructions[5].NormalizedOpCode == NormalizedByteCode.__iconst && method.Instructions[5].Arg1 == 0 &&
1351 method.Instructions[6].NormalizedOpCode == NormalizedByteCode.__putstatic && (fieldref = SafeGetFieldref(method.Instructions[6].Arg1)) != null &&
1352 fieldref.Class == Name && fieldref.Signature == "Z" &&
1353 (field = GetField(fieldref.Name, fieldref.Signature)) != null &&
1354 field.IsStatic && field.IsFinal &&
1355 !HasBranchIntoRegion(method.Instructions, 7, method.Instructions.Length, 0, 7) &&
1356 !HasStaticFieldWrite(method.Instructions, 7, method.Instructions.Length, field) &&
1357 !HasExceptionHandlerInRegion(method.ExceptionTable, 0, 7))
1358 {
1359 field.PatchConstantValue(true);
1360 method.Instructions[0].PatchOpCode(NormalizedByteCode.__goto, 7);
1361 flags |= FLAG_HAS_ASSERTIONS;
1362 }
1363 }
1364
1365 bool IsDesiredAssertionStatusMethodref(int cpi)
1366 {
1367 return SafeGetMethodref(cpi) is ConstantPoolItemMethodref { Class: "java.lang.Class", Name: "desiredAssertionStatus", Signature: "()Z" };
1368 }
1369
1370 private static bool HasBranchIntoRegion(Method.Instruction[] instructions, int checkStart, int checkEnd, int regionStart, int regionEnd)
1371 {
1372 for (int i = checkStart; i < checkEnd; i++)
1373 {
1374 switch (instructions[i].NormalizedOpCode)
1375 {
1376 case NormalizedByteCode.__ifeq:
1377 case NormalizedByteCode.__ifne:
1378 case NormalizedByteCode.__iflt:
1379 case NormalizedByteCode.__ifge:
1380 case NormalizedByteCode.__ifgt:
1381 case NormalizedByteCode.__ifle:
1382 case NormalizedByteCode.__if_icmpeq:
1383 case NormalizedByteCode.__if_icmpne:
1384 case NormalizedByteCode.__if_icmplt:
1385 case NormalizedByteCode.__if_icmpge:
1386 case NormalizedByteCode.__if_icmpgt:
1387 case NormalizedByteCode.__if_icmple:
1388 case NormalizedByteCode.__if_acmpeq:
1389 case NormalizedByteCode.__if_acmpne:
1390 case NormalizedByteCode.__ifnull:
1391 case NormalizedByteCode.__ifnonnull:
1392 case NormalizedByteCode.__goto:
1393 case NormalizedByteCode.__jsr:
1394 if (instructions[i].TargetIndex > regionStart && instructions[i].TargetIndex < regionEnd)
1395 {
1396 return true;
1397 }
1398 break;
1399 case NormalizedByteCode.__tableswitch:
1400 case NormalizedByteCode.__lookupswitch:
1401 if (instructions[i].DefaultTarget > regionStart && instructions[i].DefaultTarget < regionEnd)
1402 {
1403 return true;
1404 }
1405 for (int j = 0; j < instructions[i].SwitchEntryCount; j++)
1406 {
1407 if (instructions[i].GetSwitchTargetIndex(j) > regionStart && instructions[i].GetSwitchTargetIndex(j) < regionEnd)
1408 {
1409 return true;
1410 }
1411 }
1412 break;
1413 }
1414 }
1415 return false;
1416 }
1417
1418 private bool HasStaticFieldWrite(Method.Instruction[] instructions, int checkStart, int checkEnd, Field field)
1419 {
1420 for (int i = checkStart; i < checkEnd; i++)
1421 {
1422 if (instructions[i].NormalizedOpCode == NormalizedByteCode.__putstatic)
1423 {
1424 ConstantPoolItemFieldref fieldref = SafeGetFieldref(instructions[i].Arg1);
1425 if (fieldref != null && fieldref.Class == Name && fieldref.Name == field.Name && fieldref.Signature == field.Signature)
1426 {
1427 return true;
1428 }
1429 }
1430 }
1431 return false;
1432 }
1433
1434 private static bool HasExceptionHandlerInRegion(Method.ExceptionTableEntry[] entries, int regionStart, int regionEnd)
1435 {
1436 for (int i = 0; i < entries.Length; i++)
1437 {
1438 if (entries[i].handlerIndex > regionStart && entries[i].handlerIndex < regionEnd)
1439 {
1440 return true;
1441 }
1442 }
1443 return false;
1444 }
1445
1447 public void Dispose()
1448 {
1449 clazz.Dispose();
1450 }
1451
1452 }
1453
1454}
global::java.lang.Class Class
global::java.lang.invoke.LambdaForm.Name Name
bool IsFinal
Gets whether this class file represents a final class.
Definition ClassFile.cs:990
static bool IsValidFieldName(ReadOnlySpan< char > name, ClassFormatVersion version)
Returns true if the given string is a valid field name given the specified class format version.
Definition ClassFile.cs:98
static bool IsValidMethodDescriptor(string descriptor)
Returns true if the specified descriptor is a valid method descriptor.
Definition ClassFile.cs:220
static bool IsValidPre49Identifier(string name)
Returns true if the given string is a valid identifier for pre-49 class files.
Definition ClassFile.cs:115
static bool IsValidMethodName(ReadOnlySpan< char > name, ClassFormatVersion version)
Returns true if the given string is a valid method name given the specified class format version.
Definition ClassFile.cs:66
static bool IsValidFieldDescriptor(string descriptor, int start, int end)
Returns true if the specified descriptor is a valid field descriptor.
Definition ClassFile.cs:165
bool IsAbstract
Gets whether this class file represents an abstract class.
Definition ClassFile.cs:985
bool IsAnnotation
Gets whether this class file represents an annotation.
bool IsInterface
Gets whether this class file represents an interface.
static bool IsValidFieldName(string name, ClassFormatVersion version)
Returns true if the given string is a valid field name given the specified class format version.
Definition ClassFile.cs:84
void Link(RuntimeJavaType thisType, LoadMode mode)
Initiates linkage of this class file to the specified java type instance.
Definition ClassFile.cs:967
static bool IsValidPre49Identifier(ReadOnlySpan< char > name)
Returns true if the given string is a valid identifier for pre-49 class files.
Definition ClassFile.cs:135
bool IsSuper
Gets whether this class file is a super.
bool IsEnum
Gets whether this class file represents an enum.
bool IsPublic
Gets whether this class file represents a public class.
Definition ClassFile.cs:995
int MajorVersion
Gets the major version of the class.
Definition ClassFile.cs:960
static bool IsValidMethodName(string name, ClassFormatVersion version)
Returns true if the given string is a valid method name given the specified class format version.
Definition ClassFile.cs:45
static bool IsValidMethodDescriptor(ReadOnlySpan< char > descriptor)
Returns true if the specified descriptor is a valid method descriptor.
Definition ClassFile.cs:233
static bool IsValidFieldDescriptor(string descriptor)
Returns true if the specified descriptor is a valid field descriptor.
Definition ClassFile.cs:152
Modifiers Modifiers
Gets the modifiers of the class.
Definition ClassFile.cs:980
static bool IsValidFieldDescriptor(ReadOnlySpan< char > descriptor)
Returns true if the specified descriptor is a valid field descriptor.
Definition ClassFile.cs:178
Maintains services relevant to an instane of the IKVM runtime.
Exposes methods to accept diagnostic invocations.